View Javadoc
1   /******************************************************************************
2    * BoardPane.java - Draw a backgammon board
3    * $Id$
4    * 
5    * BuckoFIBS - Backgammon by BuckoSoft
6    * Copyright© 2009,2010 - Dick Balaska - BuckoSoft, Corp.
7    * 
8    * $Log$
9    * Revision 1.9  2013/09/12 06:42:28  dick
10   * Animating the double cube.
11   *
12   * Revision 1.8  2013/09/10 00:21:58  dick
13   * Javadoc and debug
14   *
15   * Revision 1.7  2011/07/04 03:44:35  dick
16   * Add FirstRoll handling.
17   *
18   * Revision 1.6  2011/06/19 04:14:09  dick
19   * Send the board to the MatchStatusPanel as well.
20   *
21   * Revision 1.5  2011/06/18 19:34:09  dick
22   * Always draw red dice on CantMove.  Who cares whose dice they are.
23   * Push our resign flag a little onto his board.
24   *
25   * Revision 1.4  2011/06/05 06:56:05  dick
26   * Draw the AcceptAndWin animation.
27   *
28   * Revision 1.3  2011/06/02 19:18:30  dick
29   * Deal with painting resign.
30   *
31   * Revision 1.2  2011/05/31 19:38:56  dick
32   * Use the AnimateEventDiceRoll constants, instead of hard coded numbers.
33   *
34   * Revision 1.1  2011/05/22 22:56:08  dick
35   * c.b.f.B.g.boardTab.board becomes c.b.f.B.g.boardTab.boardPane .
36   *
37   * Revision 1.8  2011/05/22 05:24:07  dick
38   * diceUsed is always false during a DiceRoll animation.
39   *
40   * Revision 1.7  2011/05/21 05:03:02  dick
41   * Doubling functions are in the Board, not the Document.
42   * BoardPane only care about Board.
43   *
44   * Revision 1.6  2011/05/17 22:50:04  dick
45   * AnimateEvent moves to c.b.f.B.g.b.b which is where it is used.
46   *
47   * Revision 1.5  2011/05/16 21:25:56  dick
48   * Handle Home and Bar during Move.
49   *
50   * Revision 1.4  2011/05/16 14:18:41  dick
51   * Draw the CantMove event.
52   *
53   * Revision 1.3  2011/05/16 11:40:03  dick
54   * Painting animated dice rolls.
55   * More work on painting moving checkers.
56   *
57   * Revision 1.2  2011/05/15 04:38:03  dick
58   * Still draw the animation's extraCheckers even if there is no open event.
59   *
60   * Revision 1.1  2011/05/15 02:17:54  dick
61   * Move the AnimateEvents to their own package.
62   *
63   * Revision 1.11  2011/05/14 05:19:31  dick
64   * Still need work on the doubles handling for board/document split.
65   *
66   * Revision 1.10  2011/05/14 04:43:01  dick
67   * I needed to deal with some lightweight Boards.
68   * So finally make the primary document Document
69   * and demote just the Board handling to a domain object.
70   *
71   * Revision 1.9  2011/05/13 18:26:22  dick
72   * Debugging animation.
73   *
74   * Revision 1.8  2011/05/13 14:56:15  dick
75   * Add support for animating checkers on the board.
76   *
77   * Revision 1.7  2011/05/11 22:22:04  dick
78   * Working on animating checkers.
79   *
80   * Revision 1.6  2011/01/04 20:05:26  dick
81   * If there are 3 columns of checkers on a point, draw the point number in the correct y coordinate.
82   *
83   * Revision 1.5  2011/01/01 06:11:14  dick
84   * Javadoc.
85   *
86   * Revision 1.4  2010/12/29 07:50:05  dick
87   * Display the dice in grey as they are used up.
88   *
89   * Revision 1.3  2010/03/03 13:12:21  inim
90   * Replaced (c) sign in comment mangled by CVS default encoding back to UTF-8
91   *
92   * Revision 1.2  2010/03/03 12:19:49  inim
93   * Moved source to UTF8 encoding from CP1252 encoding. To this end all source files' (c) message was updated to "Copyright© 2009,2010 - Dick Balaska - BuckoSoft, Corp.". This replaces the (c) sign to UTF8, and adds the new year 2010.
94   *
95   * Revision 1.1  2010/02/04 05:57:53  inim
96   * Mavenized project folder layout
97   *
98   * Revision 1.6  2009/02/14 15:19:12  dick
99   * BuckoFIBS is released under the GNU license.
100  *
101  * Revision 1.5  2009/02/12 06:28:03  dick
102  * Add hoverTo home.
103  *
104  * Revision 1.4  2009/02/06 07:56:49  dick
105  * Working on doubles.
106  *
107  * Revision 1.3  2009/02/05 06:01:43  dick
108  * Draw the double cube being pushed.
109  * Draw the minidice.
110  *
111  * Revision 1.2  2009/01/31 06:06:55  dick
112  * If there are 6 or more checkers on a point, then draw the point number centered on #6.
113  *
114  * Revision 1.1  2009/01/28 19:37:28  dick
115  * package com.buckosoft.fibs.gui.board becomes com.buckosoft.fibs.BuckoFIBS.gui.board.
116  *
117  * Revision 1.25  2009/01/28 08:32:49  dick
118  * Turn off DEBUG.
119  *
120  * Revision 1.24  2009/01/27 05:45:39  dick
121  * Hover off of the bar.
122  *
123  * Revision 1.23  2009/01/26 06:07:34  dick
124  * I believe checkers always draw in their correct colors now.
125  *
126  * Revision 1.22  2009/01/24 17:08:36  dick
127  * Wrassle with drawing the right colored pieces in the right places.
128  *
129  * Revision 1.21  2009/01/22 05:04:49  dick
130  * More moving checkers on the board.  There are issues with playing 1-24 vs. 24-1.
131  *
132  * Revision 1.20  2009/01/20 07:42:52  dick
133  * Add hover colors and checkers.
134  *
135  * Revision 1.19  2009/01/18 05:06:08  dick
136  * mouse event handling.
137  * Add paintPointNumbers
138  * Make some methods/attributes protected so that BoardGui can get at them.
139  *
140  * Revision 1.18  2009/01/10 05:06:15  dick
141  * Fix the color of the dice, the position of the cube, and tweak the position of the bar.
142  *
143  * Revision 1.17  2009/01/08 18:47:02  dick
144  * Assign a dummy board.
145  *
146  * Revision 1.16  2009/01/08 01:34:00  dick
147  * Javadoc.
148  *
149  * Revision 1.15  2009/01/07 04:30:06  dick
150  * Javadoc.
151  *
152  * Revision 1.14  2008/12/20 23:02:40  dick
153  * Dice, checkers on bar, and double cube.
154  *
155  * Revision 1.13  2008/12/16 20:08:13  dick
156  * Start painting on the bar.
157  *
158  * Revision 1.12  2008/12/12 23:24:43  dick
159  * Switch around the colors of the dice and checkers.
160  *
161  * Revision 1.11  2008/12/12 14:45:51  dick
162  * Update drawing to the new FIBS based board (based on points instead of checkers).
163  *
164  * Revision 1.10  2008/12/12 01:19:52  dick
165  * Start reworking for a point based board,  not a checker based board.
166  *
167  * Revision 1.9  2008/12/11 09:57:25  dick
168  * Javadoc.
169  *
170  * Revision 1.8  2008/12/10 23:46:59  dick
171  * Drawing nice dice.
172  *
173  * Revision 1.7  2008/12/10 21:56:12  dick
174  * Early dice drawing.
175  *
176  * Revision 1.6  2008/12/08 10:17:15  dick
177  * Display the checkers on the board.
178  *
179  * Revision 1.5  2008/12/08 06:45:39  dick
180  * Drawing checkers in the home position.
181  *
182  * Revision 1.4  2008/04/07 06:13:26  dick
183  * Generalize calculating the board's points.
184  *
185  * Revision 1.3  2008/04/05 01:43:22  dick
186  * Draw the points.
187  */
188 
189 /* 
190  * This program is free software: you can redistribute it and/or modify
191  * it under the terms of the GNU General Public License as published by
192  * the Free Software Foundation, either version 3 of the License, or
193  * (at your option) any later version.
194  *
195  * This program is distributed in the hope that it will be useful,
196  * but WITHOUT ANY WARRANTY; without even the implied warranty of
197  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
198  * GNU General Public License for more details.
199  *
200  * You should have received a copy of the GNU General Public License
201  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
202  *
203  * The Original Code is BuckoFIBS, <http://www.buckosoft.com/BuckoFIBS/>.
204  * The Initial Developer of the Original Code is Dick Balaska and BuckoSoft, Corp.
205  * 
206  */
207 package com.buckosoft.fibs.BuckoFIBS.gui.boardTab.boardPane;
208 
209 import java.awt.Color;
210 import java.awt.Dimension;
211 import java.awt.Font;
212 import java.awt.FontMetrics;
213 import java.awt.Graphics;
214 import java.awt.Point;
215 
216 import javax.swing.JPanel;
217 
218 import org.slf4j.Logger;
219 import org.slf4j.LoggerFactory;
220 
221 import com.buckosoft.fibs.BuckoFIBS.BFProperties;
222 import com.buckosoft.fibs.BuckoFIBS.gui.boardTab.BoardTab;
223 import com.buckosoft.fibs.BuckoFIBS.gui.boardTab.boardPane.AnimateEvent.Type;
224 import com.buckosoft.fibs.domain.Board;
225 
226 /** Draw a backgammon board. <br>
227  * checker width is a root.<br>
228  * There are 16.5 checker widths in a board.<br>
229  * 12 points<br>
230  * 1.5 left side, right side, bar.<br>
231  * ebeh, still need to make sure that 5 checkers will fit on a point.
232  * @author Dick Balaska
233  * @since 2008/04/01
234  * @version $Revision$ <br> $Date$
235  * @see <a href="http://cvs.buckosoft.com/Projects/BuckoFIBS/BuckoFIBS/src/main/java/com/buckosoft/fibs/BuckoFIBS/gui/boardTab/BoardPane.java">cvs BoardPane.java</a>
236  */
237 public class BoardPane extends JPanel {
238 	private	final static boolean DEBUG = false;
239 	private	final static boolean DEBUGa = false;		// animate foo
240     private Logger logger = LoggerFactory.getLogger(getClass());
241 	private static final long serialVersionUID = 1L;
242 	
243 	
244 	// Assign a dummy board, just so Visual Editor will have something to draw.
245 	// This will get overwritten by the real board during runtime.
246 	protected	Board			board = new Board();  //  @jve:decl-index=0:
247 	//protected	Document		document;
248 	private		BoardTab		boardTab = null;
249 	protected	BFProperties	properties = null;
250 
251 	/** Drawing dimensions and hints */
252 	public		BoardSpecs bs = new BoardSpecs();  //  @jve:decl-index=0:
253 
254 	private	Color	boxColor = Color.darkGray;  //  @jve:decl-index=0:
255 	private	Color	boardColor = Color.lightGray;  //  @jve:decl-index=0:
256 	private	Color	bPointColor = Color.pink;  //  @jve:decl-index=0:
257 	private	Color	wPointColor = Color.red;  //  @jve:decl-index=0:
258 	private	Color	bCheckerColor = Color.black;
259 	private	Color	bTrimColor = Color.white;
260 	private	Color	wCheckerColor = Color.white;
261 	private Color	wGreyColor = Color.gray;
262 	private	Color	wTrimColor = Color.black;
263 	
264 //	private	Color	hoverColor = Color.lightGray;
265 	private	Color	hoverColor = new Color(200,200,200,192);
266 //	private	Color	hoverToColor = Color.yellow;
267 	private	Color	hoverToColor = new Color(255,255,0,150);
268 	
269 	protected static final int POINT_UNKNOWN = -1;
270 	protected static final int POINT_BAR = -2;
271 	protected static final int POINT_DICE = -3;
272 	protected static final int POINT_DOUBLE = -4;
273 	protected static final int POINT_BAR_DICE = -5;
274 	protected static final int POINT_REJECT = -6;
275 	
276 	
277 
278 	protected int	hoverPoint = POINT_UNKNOWN;
279 	
280 	/** 1-24 are any "shadow" checkers on a point */
281 	protected int[] hoverTo = new int[26];
282 	
283 	/** Used for drawing the points */
284 	private	int[] xPoints = new int[4];
285 	/** Used for drawing the points */
286 	private int[] yPoints = new int[4];
287 
288 	protected boolean[] diceUsed = new boolean[2];
289 	
290 	protected	AnimateManager	animateManager;
291 	
292 	/** Default/only constructor */
293 	public BoardPane() {
294 		super();
295 		initialize();		
296 		this.animateManager = new AnimateManager();
297 		this.animateManager.setBoardPane(this);
298 		this.animateManager.setProperties(properties);
299 	}
300 
301 	/** Precalculate the dimensions of a board for drawing
302 	 * @author Dick Balaska
303 	 * @since 2008/04/01
304 	 * @version $Revision$ <br> $Date$
305 	 * @see <a href="http://cvs.buckosoft.com/Projects/BuckoFIBS/BuckoFIBS/src/main/java/com/buckosoft/fibs/BuckoFIBS/gui/board/BoardPane.java">cvs BoardPane.java</a>
306 	 */
307 	public class BoardSpecs {
308 		/** Width of the board */
309 		public int	w;
310 		/** Height of the board */
311 		public int	h;
312 		/** diameter of a checker */
313 		public int	checkerSize;
314 		/** checkerSize * 1.5 */
315 		public int c15;
316 		/** checkerSize / 2 */
317 		public int	c2;
318 		/** checkerSize / 3 for in home */
319 		public int checkerHeight;
320 		public int dieSize;
321 		public int extra;
322 		public int barWidth;
323 		/** How tall is the point */
324 		public int	pointHeight;
325 //		public Color	cColor;
326 //		public Color	tColor;
327 	}
328 	
329 	/** Set the reference to the backgammon board.
330 	 * @param board the board to set
331 	 */
332 	public void setBoard(Board board) {
333 		this.board = board;
334 		this.boardTab.setMatchStatusPanelBoard(board);
335 	}
336 
337 	public void setBoardTab(BoardTab boardTab) {
338 		this.boardTab = boardTab;
339 	}
340 
341 
342 	/** This method initializes this
343 	 * @return void
344 	 */
345 	private void initialize() {
346 		this.setSize(400, 300);
347 		this.setPreferredSize(new Dimension(400, 300));
348 		this.addMouseListener(new java.awt.event.MouseAdapter() {   
349 			public void mousePressed(java.awt.event.MouseEvent e) {    
350 				onMousePressed(e);
351 			}
352 		});
353 		this.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
354 			public void mouseMoved(java.awt.event.MouseEvent e) {
355 				onMouseMoved(e);
356 			}
357 		});
358 	}
359 
360 	protected void setHoverPoint(int p) {
361 		if (DEBUG)
362 			System.out.println("setHoverPoint(" + p + ")");
363 		hoverPoint = p;
364 		int i;
365 		for (i=0; i<hoverTo.length; i++)
366 			hoverTo[i] = 0;
367 	}
368 
369 	protected void onMouseClicked(java.awt.event.MouseEvent e) {
370 		System.out.println("onMouseClicked: Should be overridden");
371 	}
372 
373 	protected void onMousePressed(java.awt.event.MouseEvent e) {
374 		System.out.println("onMousePressed: Should be overridden");
375 	}
376 
377 	protected void onMouseMoved(java.awt.event.MouseEvent e) {
378 		System.out.println("onMouseMoved: Should be overridden");
379 	}
380 
381 	/** Paint the entire backgammon board and all of it's pieces.
382 	 * @param g The Graphics to use
383 	 */
384 	public void paint(Graphics g) {
385 		super.paint(g);
386 		bs.w = this.getWidth();
387 		bs.h = this.getHeight();
388 		bs.checkerSize = (int)(((double)bs.w)/16.5);
389 		bs.c2 = bs.checkerSize / 2;
390 		bs.c15 = (int)((double)bs.checkerSize * 1.5);
391 		bs.checkerHeight = bs.checkerSize/3;
392 		bs.extra = bs.w-((bs.checkerSize*12)+(bs.c15*3));
393 		bs.barWidth = bs.checkerSize + bs.extra;
394 		bs.pointHeight = bs.h/2-bs.c15;		// XXX: make something up for now. This could be better.
395 
396 		// fill with the board color (shouldn't this be in "erase"?)
397 		g.setColor(boardColor);
398 		g.fillRect(0, 0, bs.w, bs.h);
399 	
400 		// draw left end
401 		g.setColor(boxColor);
402 		g.fillRect(0, 0, bs.c15, bs.h);
403 		// draw right end
404 		g.fillRect(bs.w-bs.c15, 0, bs.w, bs.h);
405 		// draw bar
406 		g.fillRect(bs.w/2-bs.barWidth/2, 0, bs.barWidth, bs.h);
407 		int x, y, w;
408 		y = bs.pointHeight;
409 		int p;
410 		for (p=1; p<=12; p++) {		// points 1-12
411 			x = getPointX(p);
412 			if ((p & 1) != 0)
413 				g.setColor(wPointColor);
414 			else
415 				g.setColor(bPointColor);
416 			xPoints[0] = x;
417 			yPoints[0] = bs.h;
418 			xPoints[1] = x+bs.c2;
419 			yPoints[1] = bs.h-y;
420 			xPoints[2] = x+bs.checkerSize;
421 			yPoints[2] = bs.h;
422 			xPoints[3] = x;
423 			yPoints[3] = bs.h;
424 			g.fillPolygon(xPoints, yPoints, 4);
425 			g.setColor(Color.black);
426 			g.drawLine(x, bs.h, x+bs.c2, bs.h-y);
427 			g.drawLine(x+bs.c2, bs.h-y, x+bs.checkerSize, bs.h);
428 		}
429 		for (p=13; p<=24; p++) {
430 			x = getPointX(p);
431 			if ((p & 1) == 1)
432 				g.setColor(wPointColor);
433 			else
434 				g.setColor(bPointColor);
435 			xPoints[0] = x;
436 			yPoints[0] = 0;
437 			xPoints[1] = x+bs.c2;
438 			yPoints[1] = y;
439 			xPoints[2] = x+bs.checkerSize;
440 			yPoints[2] = 0;
441 			xPoints[3] = x;
442 			yPoints[3] = 0;
443 			g.fillPolygon(xPoints, yPoints, 4);
444 			g.setColor(Color.black);
445 			g.drawLine(x, 0, x+bs.c2, y);
446 			g.drawLine(x+bs.c2, y, x+bs.checkerSize, 0);
447 		}
448 		paintCheckers(g);
449 		paintDice(g);
450 		paintDoubleCube(g);
451 		paintPointNumbers(g);
452 		if (this.board.isYourTurnToRollOrDouble()) {
453 			int miniDieSize = bs.barWidth/2;
454 			x = bs.w/2-bs.barWidth/2;
455 			y = bs.h-miniDieSize-2;
456 			paintDie(g, miniDieSize, x, y, 6, Color.white, Color.white, Color.black);
457 			paintDie(g, miniDieSize, x+miniDieSize, y, 6, Color.white, Color.white, Color.black);
458 			g.setColor(Color.yellow);
459 			g.drawRoundRect(x-2, y-2, miniDieSize*2+2, miniDieSize+2, miniDieSize/4+2, miniDieSize/4+2);
460 			g.drawRoundRect(x-1, y-1, miniDieSize*2+1, miniDieSize+1, miniDieSize/4+1, miniDieSize/4+1);
461 			
462 		}
463 		if (board.isAcceptDeclineDouble() || board.isAcceptDeclineResign()) {
464 			g.setColor(Color.red);
465 			x = getDeclineX();
466 			y = getDeclineY();
467 			w = bs.c15;
468 			g.drawLine(x, y, x+w, y+w);
469 			g.drawLine(x+w, y, x, y+w);
470 			g.drawLine(x+1, y, x+w+1, y+w);
471 			g.drawLine(x+w+1, y, x+1, y+w);
472 
473 		}
474 		paintResign(g);
475 		paintAnimatedCheckers(g);
476 	}
477 
478 	protected	int	getDeclineX() {
479 		return(bs.w-bs.c15);
480 	}
481 	protected	int	getDeclineY() {
482 		return(bs.h/2 - bs.c15/2);
483 	}
484 	private void paintCheckers(Graphics g) {
485 		int[] p = this.board.getPoints();
486 		int i;
487 		int j;
488 		int c;
489 		if (p == null)
490 			return;
491 		if (DEBUG)
492 			System.out.println("xo=" + board.getXO() + " dir=" + board.getDirection());
493 		for (i=1; i<=24; i++) {
494 			c = Math.abs(p[i]);
495 			if (c == 0 && hoverTo[i] == 0)
496 				continue;
497 			Color cColor = bCheckerColor;
498 			Color tColor = bTrimColor;
499 			//if (p[i]*board.getXO() > 0) {
500 			if (p[i] < 0) {
501 				if (DEBUG)
502 					System.out.println("p[" + i + "]=" + p[i]);
503 				cColor = wCheckerColor;
504 				tColor = wTrimColor;
505 			}
506 			int x = getPointX(i);
507 			for (j=0; j<c+hoverTo[i]; j++) {
508 				int y = getNthCheckerY(i, j);
509 				if (i == hoverPoint && j == c-1) 
510 					cColor = hoverColor;
511 				if (j>=c)
512 					cColor = hoverToColor;
513 				g.setColor(cColor);
514 				g.fillArc(x, y, bs.checkerSize, bs.checkerSize, 0, 360);
515 				g.setColor(tColor);
516 				g.drawArc(x, y, bs.checkerSize, bs.checkerSize, 0, 360);
517 			}
518 		}
519 		p = this.board.getHome();
520 		for (j=0; j<p[1]; j++)
521 			paintCheckerInHome(g, Board.X, j, bCheckerColor, bTrimColor);
522 		for (j=0; j<p[0]; j++)
523 			paintCheckerInHome(g, Board.O, j, wCheckerColor, wTrimColor);
524 		if (hoverTo[0] > 0)
525 			paintCheckerInHome(g, Board.O, j, hoverToColor, wTrimColor);
526 		int[] bar = board.getBar();
527 		for (j=0; j<bar[Board.O]; j++)
528 			paintCheckerOnBar(g, Board.O, j, wCheckerColor, wTrimColor);
529 		for (j=0; j<bar[Board.X]; j++)
530 			paintCheckerOnBar(g, Board.X,  j, bCheckerColor, bTrimColor);
531 	}
532 
533 	protected int getCheckerYOnBar(int who, int checker) {
534 		int y = bs.h/2 + bs.checkerSize + ((checker % 5) * bs.checkerSize);
535 		y -= (checker/5*bs.checkerHeight);
536 		if (who == Board.O)
537 			y = bs.h - bs.checkerSize -y;
538 		
539 		return(y);
540 	}
541 
542 	private void paintCheckerOnBar(Graphics g, 
543 			int who, int c, Color cColor, Color tColor) {
544 		if (hoverPoint == POINT_BAR && c == 0)
545 			cColor = hoverColor;
546 		int x = bs.w/2 - bs.checkerSize/2;
547 		int y = getCheckerYOnBar(who, c);
548 		g.setColor(cColor);
549 		g.fillArc(x, y, bs.checkerSize, bs.checkerSize, 0, 360);
550 		g.setColor(tColor);
551 		g.drawArc(x, y, bs.checkerSize, bs.checkerSize, 0, 360);
552 	}
553 
554 	protected int	getCheckerYInHome(int who, int checker) {
555 		int y;
556 		y = checker * bs.checkerHeight;
557 		if (who == Board.O)
558 			y = bs.h - (checker+1) * bs.checkerHeight;
559 		return(y);
560 	}
561 
562 	private void paintCheckerInHome(Graphics g, 
563 			int who, int checker, Color cColor, Color tColor) {
564 		int x = bs.w-(bs.c15/2)-(bs.checkerSize/2);
565 		int y = getCheckerYInHome(who, checker);
566 		g.setColor(cColor);
567 		g.fillArc(x, y, bs.checkerSize, bs.checkerHeight, 0, 180);
568 		g.setColor(tColor);
569 		g.drawArc(x, y, bs.checkerSize, bs.checkerHeight, 0, 180);
570 	}
571 
572 	/** Return the left side of a point
573 	 * @param p The point to calculate
574 	 * @return The x of the left side of the triangle
575 	 */
576 	protected int	getPointX(int p) {
577 		if (p == Board.Bar)
578 			return(bs.w/2-bs.c2);
579 		if (p == Board.Home)
580 			return(bs.w-(bs.c15/2)-(bs.checkerSize/2));
581 
582 		if (p > 12)
583 			p = 25 - p;
584 		p--;
585 		int x = (bs.w - bs.c15 - bs.checkerSize) - ((bs.checkerSize+1)*p) - 2;
586 		if (p > 5)
587 			x -= bs.barWidth + 2;
588 		return(x);
589 	}
590 
591 	/** Calculate the y for a checker
592 	 * @param p The point to calculate
593 	 * @param c The checker number on the point.  There can be between 1-15 checkers sitting on a point.
594 	 * 		    (If there's 0, then there's no point of drawing).
595 	 *			This number is 0 based.
596 	 * @return The y value to draw the checker at.
597 	 */
598 	protected int getNthCheckerY(int p, int c) {
599 		if (board.getDirection() > 0)
600 			p = 25-p;
601 		int y = (c % 5) * bs.checkerSize;
602 		y += (c/5*bs.checkerHeight);
603 		if (p <= 12)
604 			y = bs.h - bs.checkerSize -y;
605 		return(y);
606 	}
607 
608 	///////////////////////////////////////////////////////////////////////////
609 	/** Paint the dice
610 	 * @param g The Graphics we draw to
611 	 */
612 	private void paintDice(Graphics g) {
613 		Color cColor = bCheckerColor;
614 		Color tColor = bTrimColor;
615 		Color gColor = wGreyColor;
616 
617 		bs.dieSize = bs.checkerSize;
618 		int y = bs.h/2-bs.c2;
619 		int x0 = this.getPointX(9) - bs.c15;
620 		int x1 = x0+bs.c15;
621 		int size = bs.dieSize;
622 		int[][] dice = board.getDice();
623 
624 		AnimateEvent ae = this.animateManager.getHeadEvent();
625 		if (ae != null) {
626 			if (ae.getType() == Type.Roll) {
627 				AnimateEventDiceRoll aedr = (AnimateEventDiceRoll)ae;
628 				for (int i=0; i<diceUsed.length; i++)
629 					diceUsed[i] = false;
630 				if (aedr.getWho() == Board.X){
631 					int miniSize = bs.barWidth/2;
632 					int miniX = bs.w/2-bs.barWidth/2;
633 					int miniY = 0;	// bs.h-miniSize-2;
634 					int[] pos = aedr.getDiceParms(miniX, miniX+miniSize, miniY, miniSize, x0, x1, y, bs.dieSize);
635 					x0 = pos[AnimateEventDiceRoll.XL];
636 					x1 = pos[AnimateEventDiceRoll.XR];
637 					y = pos[AnimateEventDiceRoll.Y];
638 					size = pos[AnimateEventDiceRoll.SIZE];
639 					dice[Board.X][0] = aedr.dice[0];
640 					dice[Board.X][1] = aedr.dice[1];
641 				}
642 			}
643 			if (ae.getType() == Type.FirstRoll) {
644 				AnimateEventFirstRoll aefr = (AnimateEventFirstRoll)ae;
645 				for (int i=0; i<diceUsed.length; i++)
646 					diceUsed[i] = false;
647 				// Calculate the black die
648 				int miniSize = bs.barWidth/2;
649 				int miniX = bs.w/2-bs.barWidth/2;
650 				int miniY = 0;	// bs.h-miniSize-2;
651 				x0 = (int)(((x0-miniX)*ae.offset)+miniX);
652 				y =  (int)(((y-miniY)*ae.offset)+miniY);
653 				size = (int)(((bs.dieSize-miniSize)*ae.offset)+miniSize);
654 				// We have to paint the die here because Board.X is 0
655 				paintDie(g, size, x0, y, aefr.getBlackDie(), cColor, cColor, tColor);
656 
657 			}
658 			if (ae.getType() == Type.CantMove){
659 				cColor = Color.red;
660 			}
661 			if (ae instanceof AnimateEventResign) {
662 				cColor = makeTranslucent(cColor);
663 				tColor = makeTranslucent(tColor);
664 			}
665 		}
666 		// paint the black/opponent dice
667 		if (ae == null || ae.getType() != Type.FirstRoll) {
668 			if (dice[Board.X][0] != 0)
669 				paintDie(g, size, x0, y, dice[Board.X][0], cColor, cColor, tColor);
670 			if (dice[Board.X][1] != 0)
671 				paintDie(g, size, x1, y, dice[Board.X][1], cColor, cColor, tColor);
672 		}
673 		if (ae != null && ae.getType() == Type.CantMove && ae.getWho() == Board.X) {
674 			g.setColor(Color.red);
675 			y = y + size + size/2;
676 			g.drawLine(x0, y, x1+size, y-size*2);
677 			g.drawLine(x0-1, y, x1+size-1, y-size*2);
678 			g.drawLine(x0, y-size*2, x1+size, y);
679 			g.drawLine(x0-1, y-size*2, x1+size-1, y);
680 			
681 		}
682 		// Do white dice
683 		Color luColor = wCheckerColor;
684 		Color ldColor = wCheckerColor;
685 		Color ruColor = wCheckerColor;
686 		Color rdColor = wCheckerColor;
687 		tColor = wTrimColor;
688 
689 		if (diceUsed.length == 2) {
690 			if (diceUsed[0]) {
691 				luColor = gColor;
692 				ldColor = gColor;
693 			}
694 			if (diceUsed[1]) {
695 				ruColor = gColor;
696 				rdColor = gColor;
697 			}
698 		}
699 		if (diceUsed.length == 4) {
700 			if (diceUsed[3])
701 				luColor = gColor;
702 			if (diceUsed[2])
703 				ldColor = gColor;
704 			if (diceUsed[1])
705 				ruColor = gColor;
706 			if (diceUsed[0])
707 				rdColor = gColor;
708 		}
709 		x0 = this.getPointX(4);
710 		x1 = x0+bs.c15;
711 		y = bs.h/2-bs.c2;
712 		size = bs.dieSize;
713 		if (ae != null) {
714 			if (ae.getType() == Type.Roll) {
715 				AnimateEventDiceRoll aedr = (AnimateEventDiceRoll)ae;
716 				if (aedr.getWho() == Board.O){
717 					int miniSize = bs.barWidth/2;
718 					int miniX = bs.w/2-bs.barWidth/2;
719 					int miniY = bs.h-miniSize-2;
720 					int[] pos = aedr.getDiceParms(miniX, miniX+miniSize, miniY, miniSize, x0, x1, y, bs.dieSize);
721 					x0 = pos[0];
722 					x1 = pos[1];
723 					y = pos[2];
724 					size = pos[3];
725 					dice[Board.O][0] = aedr.dice[0];
726 					dice[Board.O][1] = aedr.dice[1];
727 				}
728 			}
729 			if (ae.getType() == Type.CantMove) {
730 				luColor = Color.red;
731 				ldColor = Color.red;
732 				ruColor = Color.red;
733 				rdColor = Color.red;
734 			}
735 			if (ae.getType() == Type.FirstRoll) {
736 				AnimateEventFirstRoll aefr = (AnimateEventFirstRoll)ae;
737 				// Calculate the white die
738 				int miniSize = bs.barWidth/2;
739 				int miniX = bs.w/2-bs.barWidth/2;
740 				int miniY = bs.h-miniSize-2;
741 				x0 = (int)(((x0-miniX)*ae.offset)+miniX);
742 				y =  (int)(((y-miniY)*ae.offset)+miniY);
743 				size = (int)(((bs.dieSize-miniSize)*ae.offset)+miniSize);
744 				// We have to paint the die here because Board.X is 0
745 				paintDie(g, size, x0, y, aefr.getWhiteDie(),  luColor, ldColor, tColor);
746 
747 			}
748 			if (ae instanceof AnimateEventResign) {
749 				luColor = makeTranslucent(luColor);
750 				ldColor = makeTranslucent(ldColor);
751 				ruColor = makeTranslucent(ruColor);
752 				rdColor = makeTranslucent(rdColor);
753 				tColor = makeTranslucent(tColor);
754 			}
755 		}
756 		if (ae == null || ae.getType() != Type.FirstRoll) {
757 			if (dice[Board.O][0] != 0)
758 				paintDie(g, size, x0, y, dice[Board.O][0], luColor, ldColor, tColor);
759 			if (dice[Board.O][1] != 0)
760 				paintDie(g, size, x1, y, dice[Board.O][1], ruColor, rdColor, tColor);
761 		}
762 		if (ae != null && ae.getType() == Type.CantMove && ae.getWho() == Board.O){
763 			g.setColor(Color.red);
764 			y = y + size + size/2;
765 			g.drawLine(x0, y, x1+size, y-size*2);
766 			g.drawLine(x0-1, y, x1+size-1, y-size*2);
767 			g.drawLine(x0, y-size*2, x1+size, y);
768 			g.drawLine(x0-1, y-size*2, x1+size-1, y);
769 		}
770 	}
771 	
772 	/*  0   4
773 	 *  1 3 5
774 	 *  2   6
775 	 */
776 	private final static boolean[][] diePoints = new boolean[][] {
777 		{false,false,false,false,false,false,false},	// 0
778 		{false,false,false,true,false,false,false},		// 1
779 		{false,false,true,false,true,false,false},		// 2
780 		{false,false,true,true,true,false,false},		// 3
781 		{true,false,true,false,true,false,true},		// 4
782 		{true,false,true,true,true,false,true},			// 5
783 		{true,true,true,false,true,true,true},			// 6
784 	};
785 	private	final static double y0m = 25.0/100.0;
786 	private	final static double y2m = 75.0/100.0;
787 
788 	/** Paint one die on the board
789 	 * @param g The graphics to use
790 	 * @param dieSize The number of pixels to draw the die in
791 	 * @param x The left side of the die
792 	 * @param y The bottom of the die
793 	 * @param n The number of dots to draw (value of the die)
794 	 * @param uColor The top half color
795 	 * @param dColor The bottom half color
796 	 * @param tColor The trim (border) color
797 	 */
798 	private void paintDie(Graphics g, int dieSize,
799 						  int x, int y, int n, Color uColor, Color dColor, Color tColor) {
800 		int dotSize = dieSize/4;
801 		int dotSize2 = dotSize/2;
802 		g.setColor(uColor);
803 		g.setClip(x-1, y+0, dieSize+1, dieSize/2+1);
804 		g.fillRoundRect(x, y, dieSize, dieSize, dieSize/4, dieSize/4);
805 		g.setColor(dColor);
806 		g.setClip(x-1, y+dieSize/2+1, dieSize+1, dieSize/2+1);
807 		g.fillRoundRect(x, y, dieSize, dieSize, dieSize/4, dieSize/4);
808 		g.setClip(null);
809 		g.setColor(tColor);
810 		g.drawRoundRect(x, y, dieSize, dieSize, dieSize/4, dieSize/4);
811 		int dX[] = new int[3];
812 		int dY[] = new int[3];
813 		dX[0] = (int)(x + ((double)dieSize * y0m)) - dotSize2;
814 		dX[1] = (int)(x + ((double)dieSize / 2.0)) - dotSize2;
815 		dX[2] = (int)(x + ((double)dieSize * y2m)) - dotSize2;
816 		dY[0] = (int)(y + ((double)dieSize * y0m)) - dotSize2;
817 		dY[1] = (int)(y + ((double)dieSize / 2.0)) - dotSize2;
818 		dY[2] = (int)(y + ((double)dieSize * y2m)) - dotSize2;
819 		/*  0   4
820 		 *  1 3 5
821 		 *  2   6
822 		 */
823 		if (diePoints[n][0])
824 			g.fillArc(dX[0], dY[0], dotSize, dotSize, 0, 360);
825 		if (diePoints[n][1])
826 			g.fillArc(dX[0], dY[1], dotSize, dotSize, 0, 360);
827 		if (diePoints[n][2])
828 			g.fillArc(dX[0], dY[2], dotSize, dotSize, 0, 360);
829 		if (diePoints[n][3])
830 			g.fillArc(dX[1], dY[1], dotSize, dotSize, 0, 360);
831 		if (diePoints[n][4])
832 			g.fillArc(dX[2], dY[0], dotSize, dotSize, 0, 360);
833 		if (diePoints[n][5])
834 			g.fillArc(dX[2], dY[1], dotSize, dotSize, 0, 360);
835 		if (diePoints[n][6])
836 			g.fillArc(dX[2], dY[2], dotSize, dotSize, 0, 360);
837 	}
838 
839 
840 	Font	doubleCubeFont = new Font("Arial", Font.BOLD, 18);
841 
842 	private void paintDoubleCube(Graphics g) {
843 		Point p = getDoubleCubeXY();
844 		int w2 = getDoubleCubeWidth()/2;
845 		int x = p.x - w2;
846 		int y = p.y - w2;
847 		AnimateEvent ae = animateManager.getHeadEvent();
848 		if (ae != null) {
849 			AnimateEventDouble aed = null;
850 			if (ae.getType() == Type.Double) {
851 				aed = (AnimateEventDouble)ae;
852 				if (properties.isDEBUG_ShowAnimatePath()) {
853 					aed.calculate(board);
854 					g.setColor(Color.blue);
855 					for (double d = 0.0; d <= 1.0; d += 0.002) {
856 						int pp[] = aed.getXY(d);
857 						g.drawRect(pp[0]-1, pp[1]-1, 3, 3);
858 					}
859 					g.setColor(Color.green);
860 						for (int i=0; i<aed.x.length; i++ ) {
861 							g.drawRect((int)aed.x[i]-3, (int)aed.y[i]-3, 6, 6);		
862 						}
863 				}
864 				int[] xy = aed.getXY(aed.getOffset());
865 				x = xy[0] - w2;
866 				y = xy[1] - w2;
867 			}
868 		}
869 		//logger.info("paintdoubleCube x/y = " + x + "/" + y);
870 		int cubeValue = board.getCube();
871 		int w = getDoubleCubeWidth();
872 		if (board.getWasDoubled()[0] || board.getWasDoubled()[1]) {
873 			cubeValue *= 2;
874 			if (cubeValue > 64)
875 				cubeValue = 1;
876 		}
877 		g.setColor(Color.white);
878 		g.fillRoundRect(x, y, w, w, w/4, w/4);
879 		g.setColor(Color.black);
880 		g.drawRoundRect(x, y, w, w, w/4, w/4);
881 		g.setColor(Color.yellow);
882 		if (this.board.isYourTurnToRollOrDouble()) {
883 			g.drawRoundRect(x, y, w, w, w/4, w/4);
884 			g.drawRoundRect(x-1, y-1, w+2, w+2, w/4+1, w/4+1);
885 		}
886 
887 		g.setColor(Color.black);
888 		g.setFont(doubleCubeFont);
889 		FontMetrics fm = g.getFontMetrics();
890 		String s = "" + cubeValue; 
891 		int sw = fm.stringWidth(s);
892 		x = x + w/2 - sw/2;
893 		y = y + w/2 - fm.getAscent()/2 + fm.getAscent();
894 		g.drawString(s, x, y);
895 	}
896 
897 	protected Point getDoubleCubeXY() {
898 		int w = getDoubleCubeWidth();
899 		int x = bs.c15/2;
900 		int y = bs.h/2;
901 		if (board.getHasCube() == Board.O)
902 			y = 0 + w;
903 		if (board.getHasCube() == Board.X)
904 			y = bs.h - w*2;
905 		if (board.getWasDoubled()[0]) {
906 			logger.info("wasDoubled[0]");
907 			return(getDoubleCubePushXY());
908 		}
909 		if (board.getWasDoubled()[1]) {
910 			logger.info("wasDoubled[1]");
911 			return(getDoubleCubePushXY());
912 		}
913 		return(new Point(x,y));
914 	}
915 
916 	// XXX
917 	protected Point getDoubleCubePushXY() {
918 		int[] bp = board.getPoints();
919 		//final int[] points0 = new int[] {8,  9,10, 5, 4, 3, 2,11,12, 6, 1};
920 		//final int[] points1 = new int[] {17,16,15,20,21,22,23,14,18,13,24};
921 		final int[] points1 = new int[] { 4, 5, 3, 2, 8, 9,10,11, 1, 7,12,19};
922 		final int[] points0 = new int[] {21,20,22,23,17,16,15,14,24,18,13,6};
923 		int[] check = points1;
924 		int dir = Board.turnO;
925 		AnimateEvent ae = animateManager.getHeadEvent();
926 		if (ae != null) {
927 			AnimateEventDouble aed;
928 			if (ae.getType() == Type.Double) {
929 				aed = (AnimateEventDouble)ae;
930 				board.setWasDoubled(aed.getWhoDoubled());
931 				logger.info("(aed) set board.wasdoubled(" + Board.getXOAsText(aed.getWhoDoubled()) + ")");
932 /*				if (aed.getWhoDoubled() == Board.turnO) {
933 					check = points0;
934 					dir = Board.turnX;
935 					logger.info("(aed) use other points1;");
936 				}
937 */			}
938 		}
939 		logger.info("wasDoubled[0/1] = " + board.getWasDoubled()[0] + "/" + board.getWasDoubled()[1] + " dir = " + Board.getTurnAsText(board.getDirection()));
940 		if ((board.getWasDoubled()[Board.X] && board.getDirection() == Board.turnO)
941 		 || (board.getWasDoubled()[Board.O] && board.getDirection() == Board.turnX)) {
942 			check = points0;
943 			dir = Board.turnX;
944 			logger.info("use other points0;");
945 		}
946 		int f = 0;
947 		int h = 0;
948 		for (h = 0; h < 2; h++) {
949 			for (int i : check) {
950 				if (bp[i] == 0) {
951 					f = i;
952 					break;
953 				}
954 			}
955 			if (f != 0)
956 				break;
957 		}
958 		int x = getPointX(f);
959 		logger.info("f = " + f + " h = " + h);
960 		x += bs.c2;
961 		int y = bs.checkerSize * (h+1) + getDoubleCubeWidth()/2;
962 		if (dir == Board.turnX) {
963 			y = bs.h - y; // - getDoubleCubeWidth();
964 			logger.info("dir = turnX");
965 		}
966 		//logger.info("push x/y = " + x + "/" + y);
967 		return(new Point(x,y));
968 	}
969 
970 	protected int getDoubleCubeWidth() {
971 		return((bs.c15 + bs.dieSize) / 2);
972 	}
973 
974 	Font	pointNumbersFont = new Font("Arial", Font.BOLD, 11);
975 	private void paintPointNumbers(Graphics g) {
976 		if (!this.properties.isShowPointNumbers())
977 			return;
978 		int p;
979 		int x,y;
980 		String s;
981 		int f = 0;
982 		int t;
983 		boolean reverse = board.getDirection() > 0;
984 		g.setFont(pointNumbersFont);
985 		FontMetrics fm = g.getFontMetrics();
986 		for (p=1; p<=12; p++) {
987 			f = p;
988 			if (reverse)
989 				f = 25-p;
990 			s = "" + f;
991 			int sw = fm.stringWidth(s);
992 			x = getPointX(p) + bs.c2 - sw/2;
993 			y = bs.h - bs.c2 + fm.getAscent()/2;
994 			t = board.getPoints()[f];
995 			if (t < -5 || t > 5)
996 				y = this.getNthCheckerY(f, 5) + bs.c2 + fm.getAscent()/2;
997 //			g.setColor(Color.red);
998 //			g.drawRect(x-1, y-1, 3, 3);
999 			if (t > 0)
1000 				g.setColor(Color.white);
1001 			else
1002 				g.setColor(Color.blue);
1003 			g.drawString(s, x, y);
1004 		}
1005 		for (p=13; p<=24; p++) {
1006 			f = p;
1007 			if (reverse)
1008 				f = 25-p;
1009 			s = "" + f;
1010 			int sw = fm.stringWidth(s);
1011 			x = getPointX(p) + bs.c2 - sw/2;
1012 			y = bs.c2 + fm.getAscent()/2;
1013 			t = board.getPoints()[f];
1014 			if (t < -5 || t > 5)
1015 				y = this.getNthCheckerY(f, 5) + bs.c2 + fm.getAscent()/2;
1016 			if (t < -10 || t > 10)
1017 				y = this.getNthCheckerY(f, 10) + bs.c2 + fm.getAscent()/2;
1018 				
1019 			if (t > 0)
1020 				g.setColor(Color.white);
1021 			else
1022 				g.setColor(Color.blue);
1023 			g.drawString(s, x, y);
1024 		}
1025 	}
1026 
1027 	/** Callback from AnimationManager to refresh the whole BoardTab
1028 	 */
1029 	public void	updateBoardTab() {
1030 		this.boardTab.updateBoard();
1031 	}
1032 
1033 	/** Given a Color, return a translucent copy of that color
1034 	 * @param c The color to translucify
1035 	 * @return
1036 	 */
1037 	private Color	makeTranslucent(Color c) {
1038 		return(new Color(c.getRed(), c.getGreen(), c.getBlue(), 48));
1039 	}
1040 
1041 	private	static 	final Color	endColor = new Color(20,255,20,150);
1042 	private void	paintAnimatedCheckers(Graphics g) {
1043 		AnimateEvent ae = animateManager.getHeadEvent();
1044 		if (ae != null) {
1045 			AnimateEventMove aem = null;
1046 			if (ae.getType() == Type.Move) {
1047 				aem = (AnimateEventMove)ae;
1048 				if (properties.isDEBUG_ShowAnimatePath()) {
1049 					aem.calculate();
1050 					g.setColor(Color.blue);
1051 					for (double d = 0.0; d <= 1.0; d += 0.002) {
1052 						int p[] = aem.getXY(d);
1053 						g.drawRect(p[0]-1, p[1]-1, 3, 3);
1054 					}
1055 					g.setColor(Color.green);
1056 					for (int i=0; i<aem.x.length; i++ ) {
1057 						g.drawRect((int)aem.x[i]-3, (int)aem.y[i]-3, 6, 6);		
1058 					}
1059 				}
1060 				g.setColor(aem.getColor(aem.getOffset()));
1061 				int[] xy = aem.getXY(aem.getOffset());
1062 				g.fillArc(xy[0]-bs.c2, xy[1]-bs.c2, bs.checkerSize, bs.checkerSize, 0, 360);
1063 			}
1064 		}
1065 		if (animateManager.extraCheckersIndex != 0) {
1066 			if (DEBUGa) {
1067 				logger.debug("extraCheckers: " + (animateManager.extraCheckersIndex/2));
1068 				for (int i=0; i<animateManager.extraCheckersIndex; i+=2)
1069 					logger.debug("checker[" + i + "]=" + animateManager.extraCheckers[i] + "/" + animateManager.extraCheckers[i+1]);
1070 			}
1071 			g.setColor(endColor);
1072 			for (int i=0; i<animateManager.extraCheckersIndex; i+=2) {
1073 				if (animateManager.extraCheckers[i] == Board.Home) {
1074 					paintCheckerInHome(g, animateManager.extraCheckersWho, animateManager.extraCheckers[i+1], endColor, endColor);
1075 				//} else if (animateManager.extraCheckers[i] == Board.Bar) {
1076 					
1077 				} else {
1078 					int x = getPointX(animateManager.extraCheckers[i]);
1079 					int y = this.getNthCheckerY(animateManager.extraCheckers[i], animateManager.extraCheckers[i+1]);
1080 					g.fillArc(x, y, bs.checkerSize, bs.checkerSize, 0, 360);
1081 				}
1082 			}
1083 		}
1084 //		g.setColor(Color.black);
1085 //		g.fillArc(xy[0]-bs.c2, xy[1]-bs.c2, bs.checkerSize, bs.checkerSize, 0, 360);
1086 	}
1087 	
1088 	private void paintResign(Graphics g) {
1089 		AnimateEvent ae = this.animateManager.getHeadEvent();
1090 		if (ae != null && ae instanceof AnimateEventResign) {	// ().getType() == Type.Resign || ae.getType() == Type.PleaseAcceptOrRejectResign)) {
1091 			AnimateEventResign aer = (AnimateEventResign)ae;
1092 			int flagSize = (int)(bs.checkerSize*2.5);
1093 			int miniSize = bs.barWidth/2;
1094 			int miniX = bs.w/2-bs.barWidth/2;
1095 			int miniY = 0;	// bs.h-miniSize-2;
1096 //			int y = bs.h/2-bs.c2;
1097 			int y = (int)(bs.h-bs.pointHeight-(flagSize*0.75));
1098 			int x = this.getPointX(4); // - bs.c15;
1099 			if (aer.getWho() == Board.O){
1100 				miniY = bs.h-miniSize-2;
1101 				x = this.getPointX(9) - bs.c15;
1102 				y = (int)(0+bs.pointHeight-(flagSize*0.25));
1103 			}
1104 			int[] pos = aer.getFlagParms(miniX, miniY, miniSize, x, y, flagSize);
1105 			g.drawImage(aer.getIcon().getImage(), pos[AnimateEventResign.X], pos[AnimateEventResign.Y],
1106 					pos[AnimateEventResign.WIDTH], pos[AnimateEventResign.HEIGHT], null);
1107 			Font f = doubleCubeFont;		// XXX: Should calculate our own font, use this for now
1108 			g.setFont(f);
1109 			g.setColor(Color.black);
1110 			g.drawString("" + aer.getResigningPoints(), 
1111 					(int)(pos[AnimateEventResign.X]+pos[AnimateEventResign.WIDTH]*0.25), 
1112 					(int)(pos[AnimateEventResign.Y]+pos[AnimateEventResign.HEIGHT]*0.30));
1113 			if (ae instanceof AnimateEventRejectResign) {
1114 				g.setColor(Color.red);
1115 				g.drawLine(pos[AnimateEventResign.X],
1116 						   pos[AnimateEventResign.Y],
1117 						   pos[AnimateEventResign.X]+pos[AnimateEventResign.WIDTH],
1118 						   pos[AnimateEventResign.Y]+pos[AnimateEventResign.HEIGHT]);
1119 				g.drawLine(pos[AnimateEventResign.X]+1,
1120 						   pos[AnimateEventResign.Y],
1121 						   pos[AnimateEventResign.X]+pos[AnimateEventResign.WIDTH]+1,
1122 						   pos[AnimateEventResign.Y]+pos[AnimateEventResign.HEIGHT]);
1123 				if (ae.getOffset() > 0.5) {
1124 					g.drawLine(pos[AnimateEventResign.X]+pos[AnimateEventResign.WIDTH],
1125 							pos[AnimateEventResign.Y],
1126 							pos[AnimateEventResign.X],
1127 							pos[AnimateEventResign.Y]+pos[AnimateEventResign.HEIGHT]);
1128 					g.drawLine(pos[AnimateEventResign.X]+pos[AnimateEventResign.WIDTH]+1,
1129 							pos[AnimateEventResign.Y],
1130 							pos[AnimateEventResign.X]+1,
1131 							pos[AnimateEventResign.Y]+pos[AnimateEventResign.HEIGHT]);
1132 				}
1133 			} else if (ae instanceof AnimateEventAcceptAndWin) {
1134 				AnimateEventAcceptAndWin aeaaw = (AnimateEventAcceptAndWin)ae;
1135 				pos = aeaaw.getFlagParms(miniX, miniY, miniSize, x, y, flagSize);
1136 				g.drawImage(aer.getIcon().getImage(), pos[AnimateEventResign.X], pos[AnimateEventResign.Y],
1137 						pos[AnimateEventResign.WIDTH], pos[AnimateEventResign.HEIGHT], null);
1138 				
1139 			}
1140 		}
1141 	}
1142 }