· 10 years ago · Sep 22, 2016, 01:56 AM
1//-----------------------------------------------------------------------------
2// PURPOSE: To play a chess game between players on same or different computers.
3//
4// NOTES: To play a game between players on the same computer, uncheck the
5// 'Play game on the network?' checkbox in the 'Configure Chess Game'
6// dialog.
7//
8// To play a game between two players running the program on different
9// computers, both players must check the above checkbox. Then one and
10// only one of the players must configure the game on their localhost,
11// that is, check the 'Configure Game on localhost' checkbox. The other
12// player must enter the name or IP address of the configuration machine
13// in the 'Game Server Address' control. Both players must enter the same
14// name for the game, and the one playing the black side should check
15// the 'Play Black' checkbox.
16//
17// LICENSE: See the end of this file for important license information.
18//-----------------------------------------------------------------------------
19
20//-----------------------------------------------------------------------------
21// Include files
22//-----------------------------------------------------------------------------
23#include <cvinetv.h>
24#include <toolbox.h>
25#include <utility.h>
26#include "resource.h"
27
28//-----------------------------------------------------------------------------
29// Constants
30//-----------------------------------------------------------------------------
31#define PANEL_WIDTH 400
32#define PANEL_HEIGHT 400
33#define GRID_SIZE 8
34#define CELL_WIDTH (PANEL_WIDTH / GRID_SIZE)
35#define CELL_HEIGHT (PANEL_HEIGHT / GRID_SIZE)
36#define COLOR_WHITE VAL_OFFWHITE
37#define COLOR_BLACK VAL_DK_CYAN
38#define COLOR_CHECK VAL_RED
39#define COLOR_HILITE VAL_GRAY
40
41//-----------------------------------------------------------------------------
42// Types
43//-----------------------------------------------------------------------------
44typedef enum { White = 0, Black } Color;
45typedef enum { NoPiece = 0, Pawn, Knight, Bishop, Rook, Queen, King } PieceType;
46typedef struct Piece
47{
48 PieceType type;
49 Color color;
50} Piece;
51typedef struct Move
52{
53 Point src;
54 Point dest;
55} Move;
56
57//-----------------------------------------------------------------------------
58// Global variables
59//-----------------------------------------------------------------------------
60static CNVSubscriber reader;
61static CNVWriter writer;
62static int playingBlack, ignoreNVData, receivingMove, playingOnNetwork,
63 userClosedGame, configureNetwork;
64static char gameName[64];
65static int panel, table, promotionPanel;
66static Piece pieces[GRID_SIZE][GRID_SIZE], emptyCell = { NoPiece, -1 };
67static int whiteImages[GRID_SIZE], blackImages[GRID_SIZE];
68static Color currPlayer = White;
69static Point invalidLoc = {-1,-1};
70static Move invalidMove = { {-1,-1}, {-1,-1} }, prevMove = { {-1,-1}, {-1,-1} },
71 currMove = { {-1,-1}, {-1,-1} };
72static int kingsMoved[2], rooksMoved[2][2];
73
74//-----------------------------------------------------------------------------
75// Function prototypes
76//-----------------------------------------------------------------------------
77static int IsCurrentKingInCheck(void);
78static Color GetCellColor(Point *index);
79static int GetPieceImage(Piece *piece);
80static Point IndexToPoint(Point *index);
81static Point PointToIndex(Point *index);
82static int UpdateCellImage(Point *index);
83static int ConvertPanelCoordsToCellIndices(int *x, int *y);
84static int PointCompare(Point *pt1, Point *pt2);
85static Piece * GetPiece(Point *index);
86static int IsPathBlocked(Move *move);
87static int IsMoveable(Point *src, Point *dest);
88static int IsCellInCheck(Point *cell);
89static int IsMoveLegal(Move *move);
90static int MakeMove(Move *move, PieceType *pawnPromotionType);
91static int IsMoveInvalid(Move *move);
92static int HighlightCell(Point *index, int check);
93static int ConfigureNetwork(void);
94static void DisposeNetwork(void);
95static int ProcessReceivedData(CNVData nvData);
96static void CVICALLBACK DataCallback(void * handle, CNVData data, void * callbackData);
97static int CVICALLBACK PanelCallback(int panel, int event, void *cb, int e1, int e2);
98static int CVICALLBACK TableCallback(int panel, int ctrl, int event, void *cb, int e1, int e2);
99
100//-----------------------------------------------------------------------------
101/// HIFN This is the program entry-point function.
102//-----------------------------------------------------------------------------
103int main (int argc, char *argv[])
104{
105 int error = 0, rsrcPanel = 0;
106 PieceType pieceType;
107 Rect gridRect;
108 Point index;
109 char title[256] = "Chess";
110
111 // Configure network connections
112 errChk(ConfigureNetwork());
113 if (error)
114 goto Error;
115 if (playingOnNetwork)
116 {
117 if (gameName[0] != '\0')
118 {
119 strcat(title, "Game: ");
120 strcat(title, gameName);
121 }
122 strcat(title, ", Player: ");
123 strcat(title, playingBlack ? "Black" : "White");
124 }
125
126 // Load image and other resources
127 errChk(LoadPanel(0, "resource.uir", PANEL));
128 rsrcPanel = error;
129 errChk(LoadPanel(0, "resource.uir", PROMOTION));
130 promotionPanel = error;
131
132 // Create the user interface panel for the board
133 errChk(NewPanel(0, title, VAL_AUTO_CENTER, VAL_AUTO_CENTER, PANEL_HEIGHT, PANEL_WIDTH));
134 panel = error;
135 errChk(InstallPanelCallback(panel, PanelCallback, 0));
136 errChk(SetPanelAttribute(panel, ATTR_CAN_MAXIMIZE, 0));
137 errChk(SetPanelAttribute(panel, ATTR_SIZABLE, 0));
138
139 // Create the table control representing the board
140 errChk(NewCtrl(panel, CTRL_TABLE_LS, "", 0, 0));
141 table = error;
142 errChk(InstallCtrlCallback(panel, table, TableCallback, 0));
143 errChk(SetCtrlAttribute(panel, table, ATTR_CTRL_MODE, VAL_INDICATOR));
144 errChk(SetCtrlAttribute(panel, table, ATTR_CELL_TYPE, VAL_CELL_PICTURE));
145 errChk(SetCtrlAttribute(panel, table, ATTR_ENABLE_COLUMN_SIZING, 0));
146 errChk(SetCtrlAttribute(panel, table, ATTR_ENABLE_ROW_SIZING, 0));
147 errChk(SetCtrlAttribute(panel, table, ATTR_ENABLE_POPUP_MENU, 0));
148 errChk(SetCtrlAttribute(panel, table, ATTR_FIT_MODE, VAL_SIZE_TO_PICTURE));
149 errChk(SetCtrlAttribute(panel, table, ATTR_TABLE_MODE, VAL_GRID));
150 errChk(SetCtrlAttribute(panel, table, ATTR_COLUMN_LABELS_VISIBLE, 0));
151 errChk(SetCtrlAttribute(panel, table, ATTR_ROW_LABELS_VISIBLE, 0));
152 errChk(SetCtrlAttribute(panel, table, ATTR_SCROLL_BARS, VAL_NO_SCROLL_BARS));
153 errChk(SetCtrlAttribute(panel, table, ATTR_HEIGHT, PANEL_HEIGHT));
154 errChk(SetCtrlAttribute(panel, table, ATTR_WIDTH, PANEL_WIDTH));
155
156 // Create the grid for the board
157 errChk(InsertTableColumns(panel, table, -1, GRID_SIZE, VAL_CELL_PICTURE));
158 errChk(InsertTableRows(panel, table, -1, GRID_SIZE, VAL_CELL_PICTURE));
159 gridRect = MakeRect(1, 1, GRID_SIZE, GRID_SIZE);
160 errChk(SetTableRowAttribute(panel, table, -1, ATTR_ROW_HEIGHT, CELL_HEIGHT));
161 errChk(SetTableColumnAttribute(panel, table, -1, ATTR_COLUMN_WIDTH, CELL_WIDTH));
162 errChk(SetCtrlAttribute(panel, table, ATTR_NUM_VISIBLE_COLUMNS, GRID_SIZE));
163 errChk(SetCtrlAttribute(panel, table, ATTR_NUM_VISIBLE_ROWS, GRID_SIZE));
164
165 // Set the board square colors
166 errChk(SetTableCellRangeAttribute(panel, table, gridRect, ATTR_TEXT_BGCOLOR, COLOR_WHITE));
167 for (index.y = 0; index.y < GRID_SIZE; ++index.y)
168 for (index.x = 0; index.x < GRID_SIZE; ++index.x)
169 {
170 if (GetCellColor(&index) == Black)
171 errChk(SetTableCellAttribute(panel, table, IndexToPoint(&index),
172 ATTR_TEXT_BGCOLOR, COLOR_BLACK));
173 }
174
175 // Get the images for chess pieces
176 for (pieceType = NoPiece; pieceType < King; ++pieceType)
177 {
178 errChk(GetCtrlBitmap(rsrcPanel, PANEL_WHITE_IMAGES,
179 pieceType, &whiteImages[pieceType]));
180 errChk(GetCtrlBitmap(rsrcPanel, PANEL_BLACK_IMAGES,
181 pieceType, &blackImages[pieceType]));
182 }
183
184 // Place the pawns
185 for (index.x = 0; index.x < GRID_SIZE; ++index.x)
186 {
187 Piece *piece;
188
189 index.y = 1;
190 piece = GetPiece(&index);
191 piece->type = Pawn;
192 piece->color = Black;
193 errChk(UpdateCellImage(&index));
194 index.y = 6;
195 piece = GetPiece(&index);
196 piece->type = Pawn;
197 piece->color = White;
198 errChk(UpdateCellImage(&index));
199 }
200
201 // Place the non-pawn pieces
202 pieces[0][0].type = pieces[7][0].type = pieces[0][7].type = pieces[7][7].type = Rook;
203 pieces[0][1].type = pieces[7][1].type = pieces[0][6].type = pieces[7][6].type = Knight;
204 pieces[0][2].type = pieces[7][2].type = pieces[0][5].type = pieces[7][5].type = Bishop;
205 pieces[0][3].type = pieces[7][3].type = Queen;
206 pieces[0][4].type = pieces[7][4].type = King;
207 for (index.x = 0; index.x < GRID_SIZE; ++index.x)
208 {
209 index.y = 0;
210 GetPiece(&index)->color = Black;
211 errChk(UpdateCellImage(&index));
212 index.y = 7;
213 GetPiece(&index)->color = White;
214 errChk(UpdateCellImage(&index));
215 }
216
217 // Display the user interface
218 errChk(DisplayPanel(panel));
219
220 if (playingOnNetwork && playingBlack)
221 {
222 // If playing black, wait for white's first move.
223 errChk(SetPanelAttribute(panel, ATTR_DIMMED, 1));
224 receivingMove = 1;
225 ignoreNVData = 1; // Ignore data received via callback.
226 while (!userClosedGame)
227 {
228 CNVData data = NULL;
229 int bole = SetBreakOnLibraryErrors(0);
230 int nvErr = CNVGetConnectionAttribute(reader, CNVMostRecentDataAttribute, &data);
231 SetBreakOnLibraryErrors(bole);
232 if (nvErr >= 0 && data != NULL)
233 {
234 CNVDataType type;
235 unsigned int nDims;
236 errChk(CNVGetDataType(data, &type, &nDims));
237 if (type == CNVInt32 && nDims == 0)
238 {
239 errChk(ProcessReceivedData(data));
240 break;
241 }
242 }
243 ProcessSystemEvents();
244 }
245 ignoreNVData = 0;
246 }
247
248 // Run the user interface
249 RunUserInterface();
250
251Error:
252 // Report error if any
253 if (error < 0)
254 MessagePopup("Error", GetGeneralErrorString(error));
255 // Dispose network connections
256 DisposeNetwork();
257 // Dispose other resources
258 for (pieceType = NoPiece; pieceType < King; ++pieceType)
259 {
260 if (whiteImages[pieceType])
261 DiscardBitmap(whiteImages[pieceType]);
262 if (blackImages[pieceType])
263 DiscardBitmap(blackImages[pieceType]);
264 }
265 if (promotionPanel)
266 DiscardPanel(promotionPanel);
267 if (rsrcPanel)
268 DiscardPanel(rsrcPanel);
269 if (panel)
270 DiscardPanel(panel);
271}
272
273//-----------------------------------------------------------------------------
274/// HIFN Configures network connections.
275/// HIRET If error occurrs the return value is negative. Use the
276/// HIRET GetGeneralErrorString function to get a description of the error.
277//-----------------------------------------------------------------------------
278static int ConfigureNetwork(void)
279{
280 int error = 0, infoPanel = 0, pnl, ctrl, done = 0, waitCursor = 0;
281 CNVData nvData = 0;
282
283 errChk(LoadPanel(0, "resource.uir", INFO_PANEL));
284 infoPanel = error;
285 errChk(InstallPopup(infoPanel));
286 while (!done)
287 {
288 const char *whiteMoveVar = "white_move", *blackMoveVar = "black_move";
289 char server[128], process[128], whitePath[256], blackPath[256];
290
291 errChk(GetUserEvent(1, &pnl, &ctrl));
292 switch (ctrl)
293 {
294 case INFO_PANEL_NETWORK:
295 errChk(GetCtrlVal(infoPanel, INFO_PANEL_NETWORK, &playingOnNetwork));
296 errChk(SetCtrlAttribute(infoPanel, INFO_PANEL_BLACK, ATTR_DIMMED, !playingOnNetwork));
297 errChk(SetCtrlAttribute(infoPanel, INFO_PANEL_CONFIGURE, ATTR_DIMMED, !playingOnNetwork));
298 errChk(SetCtrlAttribute(infoPanel, INFO_PANEL_SERVER, ATTR_DIMMED, !playingOnNetwork));
299 break;
300 case INFO_PANEL_CONFIGURE:
301 errChk(GetCtrlVal(infoPanel, INFO_PANEL_CONFIGURE, &configureNetwork));
302 errChk(SetCtrlAttribute(infoPanel, INFO_PANEL_SERVER, ATTR_DIMMED, configureNetwork));
303 break;
304 case INFO_PANEL_PLAY:
305 errChk(SetWaitCursor(1));
306 waitCursor = 1;
307 errChk(GetCtrlVal(infoPanel, INFO_PANEL_NAME, gameName));
308 errChk(GetCtrlVal(infoPanel, INFO_PANEL_NETWORK, &playingOnNetwork));
309 if (playingOnNetwork)
310 {
311 strcpy(process, "Chess_");
312 strcat(process, gameName);
313 errChk(GetCtrlVal(infoPanel, INFO_PANEL_BLACK, &playingBlack));
314 errChk(GetCtrlVal(infoPanel, INFO_PANEL_CONFIGURE, &configureNetwork));
315 if (configureNetwork)
316 {
317 int exists;
318 strcpy(server, "localhost");
319 errChk(CNVProcessExists(process, &exists));
320 if (exists)
321 errChk(CNVDeleteProcess(process));
322 errChk(CNVNewProcess(process));
323 errChk(CNVStartProcess(process));
324 errChk(CNVNewVariable(process, whiteMoveVar));
325 errChk(CNVSetVariableAttribute(process, whiteMoveVar,
326 CNVVariableSingleWriterAttribute, 1));
327 errChk(CNVNewVariable(process, blackMoveVar));
328 errChk(CNVSetVariableAttribute(process, blackMoveVar,
329 CNVVariableSingleWriterAttribute, 1));
330 }
331 else
332 {
333 errChk(GetCtrlVal(infoPanel, INFO_PANEL_SERVER, server));
334 if (server[0] == '\0' || configureNetwork)
335 strcpy(server, "localhost");
336 }
337 strcpy(whitePath, "\\\\");
338 strcat(whitePath, server);
339 strcat(whitePath, "\\");
340 strcat(whitePath, process);
341 strcat(whitePath, "\\");
342 strcpy(blackPath, whitePath);
343 strcat(whitePath, whiteMoveVar);
344 strcat(blackPath, blackMoveVar);
345 errChk(CNVCreateWriter(playingBlack ? blackPath : whitePath,
346 0, 0, 10000, 0, &writer));
347 errChk(CNVCreateSubscriber(playingBlack ? whitePath : blackPath,
348 DataCallback, 0, 0, 10000, 0, &reader));
349 errChk(CNVCreateScalarDataValue(&nvData, CNVDouble, 3.14));
350 errChk(CNVWrite(writer, nvData, 10000));
351 }
352 done = 1;
353 break;
354 case INFO_PANEL_CANCEL:
355 done = 2;
356 break;
357 }
358 }
359
360Error:
361 if (nvData)
362 CNVDisposeData(nvData);
363 if (waitCursor)
364 SetWaitCursor(0);
365 if (infoPanel)
366 DiscardPanel(infoPanel);
367 if (error < 0)
368 {
369 MessagePopup("Configuration Error", GetGeneralErrorString(error));
370 return 1;
371 }
372 return done == 2 ? 1 : 0;
373}
374
375//-----------------------------------------------------------------------------
376/// HIFN Disposes network connections.
377//-----------------------------------------------------------------------------
378static void DisposeNetwork(void)
379{
380 if (!playingOnNetwork)
381 return;
382
383 if (reader)
384 CNVDispose(reader);
385 if (writer)
386 {
387 CNVData data;
388
389 CNVCreateScalarDataValue(&data, CNVInt32, 0);
390 CNVWrite(writer, data, CNVWaitForever);
391 CNVDisposeData(data);
392 CNVDispose(writer);
393 }
394
395 if (configureNetwork)
396 {
397 char process[128];
398 int exists;
399
400 strcpy(process, "Chess_");
401 strcat(process, gameName);
402 if (CNVProcessExists(process, &exists) >= 0 && exists)
403 CNVDeleteProcess(process);
404 }
405}
406
407//-----------------------------------------------------------------------------
408/// HIFN Processes network data received from the opponent.
409/// HIPAR nvData/The network variable data received from the opponent.
410/// HIRET If error occurrs the return value is negative. Use the
411/// HIRET GetGeneralErrorString function to get a description of the error.
412//-----------------------------------------------------------------------------
413static int ProcessReceivedData(CNVData nvData)
414{
415 static int notifiedGameClosure = 0;
416 int error = 0, move;
417
418 errChk(CNVGetScalarDataValue(nvData, CNVInt32, &move));
419 errChk(CNVDisposeData(nvData));
420
421 if (move == 0)
422 {
423 if (!notifiedGameClosure)
424 {
425 notifiedGameClosure = 1;
426 errChk(MessagePopup("Message", "Your opponent closed the game!"));
427 }
428 errChk(QuitUserInterface(0));
429 return 0;
430 }
431
432 if (receivingMove)
433 {
434 PieceType pawnPromotionType;
435
436 errChk(SetPanelAttribute(panel, ATTR_DIMMED, 0));
437
438 currMove.src.x = (move & 0xF);
439 currMove.src.y = (move & 0xF0) >> 4;
440 currMove.dest.x = (move & 0xF00) >> 8;
441 currMove.dest.y = (move & 0xF000) >> 12;
442 pawnPromotionType = (move & 0xF0000) >> 16;
443 errChk(MakeMove(&currMove, &pawnPromotionType));
444 prevMove = currMove;
445 currMove = invalidMove;
446 currPlayer = !currPlayer;
447 errChk(HighlightCell(&prevMove.dest, IsCurrentKingInCheck()));
448 receivingMove = 0;
449 }
450
451Error:
452 return error;
453}
454
455//-----------------------------------------------------------------------------
456/// HIFN Deferred callback function to process network data.
457/// HIPAR callbackData/The network variable data received from the opponent.
458//-----------------------------------------------------------------------------
459static void CVICALLBACK ProcessReceivedDataDeferred (void *callbackData)
460{
461 ProcessReceivedData((CNVData)callbackData);
462}
463
464//-----------------------------------------------------------------------------
465/// HIFN Network variable callback function invoked when data is received.
466/// HIPAR handle/The network variable connection receiving the data.
467/// HIPAR data/The received network variable data.
468/// HIPAR callbackData/Callback data associated with the callback function.
469//-----------------------------------------------------------------------------
470static void CVICALLBACK DataCallback(void * handle, CNVData data, void * callbackData)
471{
472 if (data)
473 {
474 if (ignoreNVData)
475 CNVDisposeData(data);
476 else
477 {
478 CNVDataType type;
479 unsigned int nDims;
480 CNVGetDataType(data, &type, &nDims);
481
482 if (type == CNVInt32 && nDims == 0)
483 PostDeferredCall(ProcessReceivedDataDeferred, data);
484 else
485 CNVDisposeData(data);
486 }
487 }
488}
489
490//-----------------------------------------------------------------------------
491/// HIFN Sends the current move through the network to the opponent.
492/// HIPAR pawnPromotionType/If the move is a pawn promotion, the piece the pawn was promoted to.
493/// HIPAR pawnPromotionType/Otherwise, this should be 'NoPiece'.
494/// HIRET If error occurrs the return value is negative. Use the
495/// HIRET GetGeneralErrorString function to get a description of the error.
496//-----------------------------------------------------------------------------
497static int SendMove(PieceType pawnPromotionType)
498{
499 CNVData nvData;
500 int error = 0, move;
501
502 move = currMove.src.x;
503 move |= currMove.src.y << 4;
504 move |= currMove.dest.x << 8;
505 move |= currMove.dest.y << 12;
506 if (pawnPromotionType != NoPiece)
507 move |= pawnPromotionType << 16;
508 errChk(CNVCreateScalarDataValue(&nvData, CNVInt32, move));
509 errChk(CNVWrite(writer, nvData, CNVWaitForever));
510 errChk(CNVDisposeData(nvData));
511
512Error:
513 return error;
514}
515
516//-----------------------------------------------------------------------------
517/// HIFN Checks if the king is in check.
518/// HIRET Non-zero if the king is in check, and zero otherwise.
519//-----------------------------------------------------------------------------
520static int IsCurrentKingInCheck(void)
521{
522 Point currKingPos;
523
524 for (currKingPos.y = 0; currKingPos.y < GRID_SIZE; ++currKingPos.y)
525 for (currKingPos.x = 0; currKingPos.x < GRID_SIZE; ++currKingPos.x)
526 {
527 Piece *piece = GetPiece(&currKingPos);
528 if (piece->type == King && piece->color == currPlayer)
529 return IsCellInCheck(&currKingPos);
530 }
531 return 0;
532}
533
534//-----------------------------------------------------------------------------
535/// HIFN Gets the color of the square at a particular index.
536/// HIPAR index/The address of the square's index.
537/// HIRET 'White' or 'Black' depending on the square's color.
538//-----------------------------------------------------------------------------
539static Color GetCellColor(Point *index)
540{
541 return (index->x + index->y) % 2 == 0 ? White : Black;
542}
543
544//-----------------------------------------------------------------------------
545/// HIFN Gets the image associated with a piece.
546/// HIPAR piece/The address of the type of piece whose image is required.
547/// HIRET The bitmap handle of the requested image.
548//-----------------------------------------------------------------------------
549static int GetPieceImage(Piece *piece)
550{
551 if (piece->type == NoPiece)
552 {
553 return 0;
554 }
555 else
556 {
557 int imageIndex = piece->type - 1;
558 return piece->color == White ? whiteImages[imageIndex] : blackImages[imageIndex];
559 }
560}
561
562//-----------------------------------------------------------------------------
563/// HIFN Converts a square's index to the associated UI co-ordinate.
564/// HIPAR index/The address of the square's index.
565/// HIRET The UI co-ordinate of the square.
566//-----------------------------------------------------------------------------
567static Point IndexToPoint(Point *index)
568{
569 return MakePoint(index->x + 1, index->y + 1);
570}
571
572//-----------------------------------------------------------------------------
573/// HIFN Converts a square's UI co-ordinate to the associated index.
574/// HIPAR point/The address of the square's UI co-ordinate.
575/// HIRET The index of the square.
576//-----------------------------------------------------------------------------
577static Point PointToIndex(Point *point)
578{
579 return MakePoint(point->x - 1, point->y - 1);
580}
581
582//-----------------------------------------------------------------------------
583/// HIFN Updates the image of a square based on current piece in the square.
584/// HIPAR index/The address of the square's index.
585/// HIRET If error occurrs the return value is negative. Use the
586/// HIRET GetGeneralErrorString function to get a description of the error.
587//-----------------------------------------------------------------------------
588static int UpdateCellImage(Point *index)
589{
590 Piece *piece = GetPiece(index);
591 int image = GetPieceImage(piece);
592 return SetTableCellAttribute(panel, table, IndexToPoint(index), ATTR_CTRL_VAL, image);
593 //return SetTableCellVal(panel, table, IndexToPoint(index), image);
594}
595
596//-----------------------------------------------------------------------------
597/// HIFN Converts panel co-ordinates to indices.
598/// HIPAR x/On input, the address of the horizontal location of the panel co-ordinate.
599/// HIPAR x/On output, contains the x index.
600/// HIPAR y/On input, the address of the vertical location of the panel co-ordinate.
601/// HIPAR y/On output, contains the y index.
602/// HIRET If error occurrs the return value is negative. Use the
603/// HIRET GetGeneralErrorString function to get a description of the error.
604//-----------------------------------------------------------------------------
605static int ConvertPanelCoordsToCellIndices(int *x, int *y)
606{
607 int error;
608
609 errChk(ConvertMouseCoordinates(panel, table, 1, 1, x, y));
610 *x /= CELL_WIDTH;
611 *y /= CELL_HEIGHT;
612 assert(*x >= 0 && *x <= GRID_SIZE - 1);
613 assert(*y >= 0 && *y <= GRID_SIZE - 1);
614
615Error:
616 return error;
617}
618
619//-----------------------------------------------------------------------------
620/// HIFN Compares two points.
621/// HIPAR pt1/First point to compare.
622/// HIPAR pt2/Second point to compare.
623/// HIRET Zero if the points are the same, otherwize non-zero.
624//-----------------------------------------------------------------------------
625static int PointCompare(Point *pt1, Point *pt2)
626{
627 int diff = pt1->x - pt2->x;
628 if (diff == 0)
629 diff = (pt1->y - pt2->y) * GRID_SIZE;
630 return diff;
631}
632
633//-----------------------------------------------------------------------------
634/// HIFN Gets the piece in a specified square.
635/// HIPAR index/The address of the square's index.
636/// HIRET Address of the piece at the specified square.
637//-----------------------------------------------------------------------------
638static Piece * GetPiece(Point *index)
639{
640 assert(index->x >= 0 && index->x <= GRID_SIZE - 1);
641 assert(index->y >= 0 && index->y <= GRID_SIZE - 1);
642 return &pieces[index->y][index->x];
643}
644
645//-----------------------------------------------------------------------------
646/// HIFN Checks if a square is occupied by any piece.
647/// HIPAR index/The address of the square's index.
648/// HIRET Zero if square is empty, non-zero if occupied by some piece.
649//-----------------------------------------------------------------------------
650static int IsCellOccupied(Point *index)
651{
652 return GetPiece(index)->type != NoPiece;
653}
654
655//-----------------------------------------------------------------------------
656/// HIFN Checks if a particular move's path is blocked.
657/// HIPAR move/The address of the move.
658/// HIRET Non-zero if the path is blocked, and zero, otherwise.
659//-----------------------------------------------------------------------------
660static int IsPathBlocked(Move *move)
661{
662 int xDiff, yDiff;
663
664 xDiff = move->dest.x - move->src.x;
665 yDiff = move->dest.y - move->src.y;
666
667 if (xDiff == 0 && yDiff == 0)
668 return 0;
669
670 if (xDiff == 0)
671 {
672 int incr;
673 Point index;
674
675 incr = yDiff > 0 ? 1 : -1;
676 index = move->src;
677 for (index.y += incr; PointCompare(&index, &move->dest) != 0; index.y += incr)
678 {
679 if (IsCellOccupied(&index))
680 return 1;
681 }
682 return 0;
683 }
684 else if (yDiff == 0)
685 {
686 int incr;
687 Point index;
688
689 incr = xDiff > 0 ? 1 : -1;
690 index = move->src;
691 for (index.x += incr; PointCompare(&index, &move->dest) != 0; index.x += incr)
692 {
693 if (IsCellOccupied(&index))
694 return 1;
695 }
696 return 0;
697 }
698 else if (abs(xDiff) == abs(yDiff))
699 {
700 int xIncr, yIncr;
701 Point index;
702
703 xIncr = xDiff > 0 ? 1 : -1;
704 yIncr = yDiff > 0 ? 1 : -1;
705 index = move->src;
706 for (index.x += xIncr, index.y += yIncr;
707 PointCompare(&index, &move->dest) != 0;
708 index.x += xIncr, index.y += yIncr)
709 {
710 if (IsCellOccupied(&index))
711 return 1;
712 }
713 return 0;
714 }
715
716 return 1;
717}
718
719//-----------------------------------------------------------------------------
720/// HIFN Checks if player can make a move between two squares.
721/// HIPAR src/The address of the source square's index.
722/// HIPAR src/The address of the target square's index.
723/// HIRET Non-zero if the move is playable, and zero otherwise.
724//-----------------------------------------------------------------------------
725static int IsMoveable(Point *src, Point *dest)
726{
727 Move move;
728
729 move.src = *src;
730 move.dest = *dest;
731 return IsMoveLegal(&move);
732}
733
734//-----------------------------------------------------------------------------
735/// HIFN Checks if a square is under attack by the opponent's pieces.
736/// HIPAR cell/The address of the square's index.
737/// HIRET Non-zero if the square is under attack, and zero otherwise.
738//-----------------------------------------------------------------------------
739static int IsCellInCheck(Point *cell)
740{
741 Point index;
742
743 for (index.y = 0; index.y < GRID_SIZE; ++index.y)
744 for (index.x = 0; index.x < GRID_SIZE; ++index.x)
745 {
746 Piece *piece = GetPiece(&index);
747
748 if (piece->type == NoPiece || piece->color == currPlayer)
749 continue;
750 if (PointCompare(&index, cell) == 0)
751 continue;
752 if (IsMoveable(&index, cell))
753 return 1;
754 }
755 return 0;
756}
757
758//-----------------------------------------------------------------------------
759/// HIFN Checks if a move is legal according to the rules of chess.
760/// HIPAR move/The address of the move.
761/// HIRET Non-zero if the move is valid, and zero otherwise.
762//-----------------------------------------------------------------------------
763static int IsMoveLegal(Move *move)
764{
765 Piece *src, *dest;
766 int xDiff, yDiff, xDiffAbs, yDiffAbs;
767
768 xDiff = move->dest.x - move->src.x;
769 yDiff = move->dest.y - move->src.y;
770 xDiffAbs = abs(xDiff);
771 yDiffAbs = abs(yDiff);
772
773 src = GetPiece(&move->src);
774 dest = GetPiece(&move->dest);
775
776 // not moving a piece
777 if (src->type == NoPiece)
778 {
779 assert_unreachable();
780 return 0;
781 }
782
783 // self-capture
784 if (dest->type != NoPiece && src->color == dest->color)
785 return 0;
786
787 switch (src->type)
788 {
789 case NoPiece:
790 assert_unreachable();
791 break;
792 case Pawn:
793 if (xDiffAbs == 0)
794 {
795 if (IsCellOccupied(&move->dest))
796 return 0;
797 if (IsPathBlocked(move))
798 return 0;
799 if (src->color == White)
800 {
801 if (move->src.y == 6)
802 return (yDiff == -1 || yDiff == -2);
803 else
804 return yDiff == -1;
805 }
806 else
807 {
808 if (move->src.y == 1)
809 return (yDiff == 1 || yDiff == 2);
810 else
811 return yDiff == 1;
812 }
813 }
814 else if (xDiffAbs == 1)
815 {
816 int enpassant = 0;
817 if (src->color == White)
818 {
819 if (yDiff != -1)
820 return 0;
821 }
822 else
823 {
824 if (yDiff != 1)
825 return 0;
826 }
827 if (!IsMoveInvalid(&prevMove))
828 {
829 Piece *prevMovePiece = GetPiece(&prevMove.dest);
830 enpassant = (prevMovePiece->type == Pawn
831 && prevMovePiece->color != src->color
832 && move->dest.x == prevMove.dest.x
833 && abs(prevMove.dest.y - prevMove.src.y) == 2
834 && prevMove.dest.y + prevMove.src.y == 2 * move->dest.y);
835 }
836 if (!enpassant && (dest->type == NoPiece || dest->color == src->color))
837 return 0;
838 return 1;
839 }
840 else
841 {
842 return 0;
843 }
844 case Knight:
845 switch (xDiffAbs)
846 {
847 case 1: return yDiffAbs == 2;
848 case 2: return yDiffAbs == 1;
849 }
850 break;
851 case Bishop:
852 if (xDiffAbs != yDiffAbs)
853 return 0;
854 if (IsPathBlocked(move))
855 return 0;
856 return 1;
857 case Rook:
858 if (xDiffAbs > 0 && yDiffAbs > 0)
859 return 0;
860 if (IsPathBlocked(move))
861 return 0;
862 return 1;
863 case Queen:
864 if (IsPathBlocked(move))
865 return 0;
866 return 1;
867 case King:
868 if (yDiffAbs > 1)
869 return 0;
870 if (xDiffAbs > 2)
871 return 0;
872 if (IsPathBlocked(move))
873 return 0;
874 if (IsCellInCheck(&move->dest))
875 return 0;
876 if (xDiffAbs == 2)
877 {
878 Point midCell;
879 int rookMovedIndex;
880
881 if (yDiffAbs != 0)
882 return 0;
883 if (kingsMoved[src->color])
884 return 0;
885 rookMovedIndex = xDiff > 0 ? 0 : 1;
886 if (rooksMoved[src->color][rookMovedIndex])
887 return 0;
888 if (IsCellInCheck(&move->src))
889 return 0;
890 midCell = move->src;
891 midCell.x += (xDiff > 0 ? 1 : -1);
892 if (IsCellOccupied(&midCell))
893 return 0;
894 if (IsCellInCheck(&midCell))
895 return 0;
896 }
897 return 1;
898 }
899
900 return 0;
901}
902
903//-----------------------------------------------------------------------------
904/// HIFN Makes the indicated move.
905/// HIPAR move/The address of the move.
906/// HIPAR pawnPromotionType/If the move resulted in a pawn promotion, on output,
907/// HIPAR pawnPromotionType/this parameter contains the type of piece promoted to.
908/// HIRET If error occurrs the return value is negative. Use the
909/// HIRET GetGeneralErrorString function to get a description of the error.
910//-----------------------------------------------------------------------------
911static int MakeMove(Move *move, PieceType *pawnPromotionType)
912{
913 static Point initRookCells[2][2] = { { {7,7}, {0,7} }, { {7,0}, {0,0} } };
914 int error = 0;
915 Piece *src, *dest;
916
917 src = GetPiece(&move->src);
918 dest = GetPiece(&move->dest);
919
920 if (src->type == Pawn)
921 {
922 // en-passant
923 if (abs(move->dest.y - move->src.y) == 1
924 && abs(move->dest.x - move->src.x) == 1
925 && !IsMoveInvalid(&prevMove)
926 && abs(prevMove.dest.y - prevMove.src.y) == 2
927 && prevMove.dest.x == prevMove.src.x
928 && prevMove.dest.y + prevMove.src.y == 2 * move->dest.y
929 && prevMove.src.x == move->dest.x
930 && GetPiece(&prevMove.dest)->type == Pawn)
931 {
932 Point enpassantIndex = MakePoint(move->dest.x, move->src.y);
933 Piece *capturedPiece = GetPiece(&enpassantIndex);
934
935 assert(PointCompare(&prevMove.dest, &enpassantIndex) == 0);
936 assert(capturedPiece->color != currPlayer);
937 *capturedPiece = emptyCell;
938 errChk(UpdateCellImage(&enpassantIndex));
939 }
940
941 // Pawn promotion
942 if ((src->color == White && move->dest.y == 0)
943 || (src->color == Black && move->dest.y == 7))
944 {
945 assert(pawnPromotionType != NULL);
946 if (*pawnPromotionType == NoPiece)
947 {
948 int pnl, ctrl;
949
950 errChk(InstallPopup(promotionPanel));
951 GetUserEvent(1, &pnl, &ctrl);
952 switch (ctrl)
953 {
954 case PROMOTION_QUEEN: *pawnPromotionType = Queen; break;
955 case PROMOTION_ROOK: *pawnPromotionType = Rook; break;
956 case PROMOTION_KNIGHT: *pawnPromotionType = Knight; break;
957 case PROMOTION_BISHOP: *pawnPromotionType = Bishop; break;
958 }
959 errChk(RemovePopup(promotionPanel));
960 }
961 src->type = *pawnPromotionType;
962 }
963 }
964 else if (src->type == King)
965 {
966 // Castling
967 int xDiff, yDiff;
968
969 xDiff = move->dest.x - move->src.x;
970 yDiff = move->dest.y - move->src.y;
971
972 if (yDiff == 0 && abs(xDiff) == 2)
973 {
974 int rookMoveIndex;
975 Move rookMove;
976
977 rookMoveIndex = xDiff > 0 ? 0 : 1;
978 rookMove.src = initRookCells[src->color][rookMoveIndex];
979 rookMove.dest = MakePoint((move->src.x + move->dest.x) / 2, move->src.y);
980 errChk(MakeMove(&rookMove, NULL));
981 }
982
983 if (!kingsMoved[src->color])
984 kingsMoved[src->color] = 1;
985 }
986 else if (src->type == Rook)
987 {
988 // Update rook flags for castling
989 if (!rooksMoved[src->color][0]
990 && PointCompare(&move->src, &initRookCells[src->color][0]) == 0)
991 rooksMoved[src->color][0] = 1;
992 if (!rooksMoved[src->color][1]
993 && PointCompare(&move->src, &initRookCells[src->color][1]) == 0)
994 rooksMoved[src->color][1] = 1;
995 }
996
997 *dest = *src;
998 *src = emptyCell;
999 errChk(UpdateCellImage(&move->src));
1000 errChk(UpdateCellImage(&move->dest));
1001
1002Error:
1003 return error;
1004}
1005
1006//-----------------------------------------------------------------------------
1007/// HIFN Checks if the input move is equal to 'invalidMove'.
1008/// HIPAR move/The address of the move.
1009/// HIRET Non-zero if the move is 'invalidMove', and zero otherwise..
1010//-----------------------------------------------------------------------------
1011static int IsMoveInvalid(Move *move)
1012{
1013 return memcmp(move, &invalidMove, sizeof(Move)) == 0;
1014}
1015
1016//-----------------------------------------------------------------------------
1017/// HIFN Highlights a square
1018/// HIPAR index/The address of the square's index.
1019/// HIPAR check/Pass non-zero if king is under check, and zero otherwise.
1020/// HIRET If error occurrs the return value is negative. Use the
1021/// HIRET GetGeneralErrorString function to get a description of the error.
1022//-----------------------------------------------------------------------------
1023static int HighlightCell(Point *index, int check)
1024{
1025 static Point prevHiliteCell = { -1, -1 };
1026 int error = 0;
1027
1028 if (prevHiliteCell.x != -1)
1029 errChk(SetTableCellAttribute(panel, table, IndexToPoint(&prevHiliteCell),
1030 ATTR_TEXT_BGCOLOR, GetCellColor(&prevHiliteCell) == White ? COLOR_WHITE : COLOR_BLACK));
1031 errChk(SetTableCellAttribute(panel, table, IndexToPoint(index),
1032 ATTR_TEXT_BGCOLOR, check ? COLOR_CHECK : COLOR_HILITE));
1033 prevHiliteCell = *index;
1034
1035Error:
1036 return error;
1037}
1038
1039//-----------------------------------------------------------------------------
1040/// HIFN Callback function associated with the user interface panel.
1041/// HIPAR panel/Handle of the panel.
1042/// HIPAR event/Event invoking the callback function.
1043/// HIPAR cb/Callback data associated with the panel.
1044/// HIPAR e1/First event data.
1045/// HIPAR e2/Second event data.
1046/// HIRET Return non-zero to swallow the event, and zero otherwise.
1047//-----------------------------------------------------------------------------
1048static int CVICALLBACK PanelCallback(int panel, int event, void *cb, int e1, int e2)
1049{
1050 if (event == EVENT_CLOSE)
1051 {
1052 QuitUserInterface(0);
1053 userClosedGame = 1;
1054 }
1055 return 0;
1056}
1057
1058//-----------------------------------------------------------------------------
1059/// HIFN Callback function associated with the table control.
1060/// HIPAR panel/Handle of the panel.
1061/// HIPAR ctrl/ID of the table control.
1062/// HIPAR event/Event invoking the callback function.
1063/// HIPAR cb/Callback data associated with the control.
1064/// HIPAR y/Vertical location of mouse click (first event data).
1065/// HIPAR x/Horizontal location of mouse click (second event data).
1066/// HIRET Return non-zero to swallow the event, and zero otherwise.
1067//-----------------------------------------------------------------------------
1068static int CVICALLBACK TableCallback(int panel, int ctrl, int event, void *cb, int y, int x)
1069{
1070 int error = 0;
1071
1072 if (event == EVENT_LEFT_CLICK_UP)
1073 {
1074 Point index;
1075 int check = 0;
1076
1077 assert(PointCompare(&currMove.dest, &invalidLoc) == 0);
1078
1079 errChk(ConvertPanelCoordsToCellIndices(&x, &y));
1080 index.x = x; index.y = y;
1081
1082 if (PointCompare(&index, &currMove.src) == 0)
1083 goto Done;
1084
1085 if (PointCompare(&currMove.src, &invalidLoc) == 0)
1086 {
1087 // Player is specifying source of move
1088 Piece *piece = GetPiece(&index);
1089 if (piece->type == NoPiece || piece->color != currPlayer)
1090 goto Error;
1091 currMove.src = index;
1092 }
1093 else
1094 {
1095 int legalMove;
1096 // Player is specifying destination of move
1097 currMove.dest = index;
1098 legalMove = IsMoveLegal(&currMove);
1099 if (legalMove)
1100 {
1101 Piece *src, *dest, tempSrc, tempDest;
1102 src = GetPiece(&currMove.src);
1103 dest = GetPiece(&currMove.dest);
1104 tempSrc = *src;
1105 tempDest = *dest;
1106 *dest = *src;
1107 *src = emptyCell;
1108 if (IsCurrentKingInCheck())
1109 legalMove = 0;
1110 *dest = tempDest;
1111 *src = tempSrc;
1112 }
1113 if (legalMove)
1114 {
1115 PieceType pawnPromotionType = NoPiece;
1116
1117 errChk(MakeMove(&currMove, &pawnPromotionType));
1118 if (playingOnNetwork)
1119 errChk(SendMove(pawnPromotionType));
1120 prevMove = currMove;
1121 currMove = invalidMove;
1122 currPlayer = !currPlayer;
1123 check = IsCurrentKingInCheck();
1124 if (playingOnNetwork)
1125 {
1126 errChk(SetPanelAttribute(panel, ATTR_DIMMED, 1));
1127 receivingMove = 1;
1128 }
1129 }
1130 else
1131 {
1132 // Make this location the source of current move, if possible
1133 Piece *piece = GetPiece(&index);
1134 currMove.dest = invalidLoc;
1135 if (piece->type == NoPiece || piece->color != currPlayer)
1136 goto Error;
1137 currMove.src = index;
1138 }
1139 }
1140
1141Done:
1142 errChk(HighlightCell(&index, check));
1143 }
1144
1145Error:
1146 assert(error >= 0);
1147 return 1;
1148}
1149
1150/******************************************************************************
1151
1152 The chess piece images used in this program are from:
1153 http://code.google.com/p/jspgnviewer
1154 and carry the following license:
1155
1156 Apache License
1157 Version 2.0, January 2004
1158 http://www.apache.org/licenses/
1159
1160 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1161
1162 1. Definitions.
1163
1164 "License" shall mean the terms and conditions for use, reproduction,
1165 and distribution as defined by Sections 1 through 9 of this document.
1166
1167 "Licensor" shall mean the copyright owner or entity authorized by
1168 the copyright owner that is granting the License.
1169
1170 "Legal Entity" shall mean the union of the acting entity and all
1171 other entities that control, are controlled by, or are under common
1172 control with that entity. For the purposes of this definition,
1173 "control" means (i) the power, direct or indirect, to cause the
1174 direction or management of such entity, whether by contract or
1175 otherwise, or (ii) ownership of fifty percent (50%) or more of the
1176 outstanding shares, or (iii) beneficial ownership of such entity.
1177
1178 "You" (or "Your") shall mean an individual or Legal Entity
1179 exercising permissions granted by this License.
1180
1181 "Source" form shall mean the preferred form for making modifications,
1182 including but not limited to software source code, documentation
1183 source, and configuration files.
1184
1185 "Object" form shall mean any form resulting from mechanical
1186 transformation or translation of a Source form, including but
1187 not limited to compiled object code, generated documentation,
1188 and conversions to other media types.
1189
1190 "Work" shall mean the work of authorship, whether in Source or
1191 Object form, made available under the License, as indicated by a
1192 copyright notice that is included in or attached to the work
1193 (an example is provided in the Appendix below).
1194
1195 "Derivative Works" shall mean any work, whether in Source or Object
1196 form, that is based on (or derived from) the Work and for which the
1197 editorial revisions, annotations, elaborations, or other modifications
1198 represent, as a whole, an original work of authorship. For the purposes
1199 of this License, Derivative Works shall not include works that remain
1200 separable from, or merely link (or bind by name) to the interfaces of,
1201 the Work and Derivative Works thereof.
1202
1203 "Contribution" shall mean any work of authorship, including
1204 the original version of the Work and any modifications or additions
1205 to that Work or Derivative Works thereof, that is intentionally
1206 submitted to Licensor for inclusion in the Work by the copyright owner
1207 or by an individual or Legal Entity authorized to submit on behalf of
1208 the copyright owner. For the purposes of this definition, "submitted"
1209 means any form of electronic, verbal, or written communication sent
1210 to the Licensor or its representatives, including but not limited to
1211 communication on electronic mailing lists, source code control systems,
1212 and issue tracking systems that are managed by, or on behalf of, the
1213 Licensor for the purpose of discussing and improving the Work, but
1214 excluding communication that is conspicuously marked or otherwise
1215 designated in writing by the copyright owner as "Not a Contribution."
1216
1217 "Contributor" shall mean Licensor and any individual or Legal Entity
1218 on behalf of whom a Contribution has been received by Licensor and
1219 subsequently incorporated within the Work.
1220
1221 2. Grant of Copyright License. Subject to the terms and conditions of
1222 this License, each Contributor hereby grants to You a perpetual,
1223 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
1224 copyright license to reproduce, prepare Derivative Works of,
1225 publicly display, publicly perform, sublicense, and distribute the
1226 Work and such Derivative Works in Source or Object form.
1227
1228 3. Grant of Patent License. Subject to the terms and conditions of
1229 this License, each Contributor hereby grants to You a perpetual,
1230 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
1231 (except as stated in this section) patent license to make, have made,
1232 use, offer to sell, sell, import, and otherwise transfer the Work,
1233 where such license applies only to those patent claims licensable
1234 by such Contributor that are necessarily infringed by their
1235 Contribution(s) alone or by combination of their Contribution(s)
1236 with the Work to which such Contribution(s) was submitted. If You
1237 institute patent litigation against any entity (including a
1238 cross-claim or counterclaim in a lawsuit) alleging that the Work
1239 or a Contribution incorporated within the Work constitutes direct
1240 or contributory patent infringement, then any patent licenses
1241 granted to You under this License for that Work shall terminate
1242 as of the date such litigation is filed.
1243
1244 4. Redistribution. You may reproduce and distribute copies of the
1245 Work or Derivative Works thereof in any medium, with or without
1246 modifications, and in Source or Object form, provided that You
1247 meet the following conditions:
1248
1249 (a) You must give any other recipients of the Work or
1250 Derivative Works a copy of this License; and
1251
1252 (b) You must cause any modified files to carry prominent notices
1253 stating that You changed the files; and
1254
1255 (c) You must retain, in the Source form of any Derivative Works
1256 that You distribute, all copyright, patent, trademark, and
1257 attribution notices from the Source form of the Work,
1258 excluding those notices that do not pertain to any part of
1259 the Derivative Works; and
1260
1261 (d) If the Work includes a "NOTICE" text file as part of its
1262 distribution, then any Derivative Works that You distribute must
1263 include a readable copy of the attribution notices contained
1264 within such NOTICE file, excluding those notices that do not
1265 pertain to any part of the Derivative Works, in at least one
1266 of the following places: within a NOTICE text file distributed
1267 as part of the Derivative Works; within the Source form or
1268 documentation, if provided along with the Derivative Works; or,
1269 within a display generated by the Derivative Works, if and
1270 wherever such third-party notices normally appear. The contents
1271 of the NOTICE file are for informational purposes only and
1272 do not modify the License. You may add Your own attribution
1273 notices within Derivative Works that You distribute, alongside
1274 or as an addendum to the NOTICE text from the Work, provided
1275 that such additional attribution notices cannot be construed
1276 as modifying the License.
1277
1278 You may add Your own copyright statement to Your modifications and
1279 may provide additional or different license terms and conditions
1280 for use, reproduction, or distribution of Your modifications, or
1281 for any such Derivative Works as a whole, provided Your use,
1282 reproduction, and distribution of the Work otherwise complies with
1283 the conditions stated in this License.
1284
1285 5. Submission of Contributions. Unless You explicitly state otherwise,
1286 any Contribution intentionally submitted for inclusion in the Work
1287 by You to the Licensor shall be under the terms and conditions of
1288 this License, without any additional terms or conditions.
1289 Notwithstanding the above, nothing herein shall supersede or modify
1290 the terms of any separate license agreement you may have executed
1291 with Licensor regarding such Contributions.
1292
1293 6. Trademarks. This License does not grant permission to use the trade
1294 names, trademarks, service marks, or product names of the Licensor,
1295 except as required for reasonable and customary use in describing the
1296 origin of the Work and reproducing the content of the NOTICE file.
1297
1298 7. Disclaimer of Warranty. Unless required by applicable law or
1299 agreed to in writing, Licensor provides the Work (and each
1300 Contributor provides its Contributions) on an "AS IS" BASIS,
1301 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1302 implied, including, without limitation, any warranties or conditions
1303 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
1304 PARTICULAR PURPOSE. You are solely responsible for determining the
1305 appropriateness of using or redistributing the Work and assume any
1306 risks associated with Your exercise of permissions under this License.
1307
1308 8. Limitation of Liability. In no event and under no legal theory,
1309 whether in tort (including negligence), contract, or otherwise,
1310 unless required by applicable law (such as deliberate and grossly
1311 negligent acts) or agreed to in writing, shall any Contributor be
1312 liable to You for damages, including any direct, indirect, special,
1313 incidental, or consequential damages of any character arising as a
1314 result of this License or out of the use or inability to use the
1315 Work (including but not limited to damages for loss of goodwill,
1316 work stoppage, computer failure or malfunction, or any and all
1317 other commercial damages or losses), even if such Contributor
1318 has been advised of the possibility of such damages.
1319
1320 9. Accepting Warranty or Additional Liability. While redistributing
1321 the Work or Derivative Works thereof, You may choose to offer,
1322 and charge a fee for, acceptance of support, warranty, indemnity,
1323 or other liability obligations and/or rights consistent with this
1324 License. However, in accepting such obligations, You may act only
1325 on Your own behalf and on Your sole responsibility, not on behalf
1326 of any other Contributor, and only if You agree to indemnify,
1327 defend, and hold each Contributor harmless for any liability
1328 incurred by, or claims asserted against, such Contributor by reason
1329 of your accepting any such warranty or additional liability.
1330
1331 END OF TERMS AND CONDITIONS
1332
1333 APPENDIX: How to apply the Apache License to your work.
1334
1335 To apply the Apache License to your work, attach the following
1336 boilerplate notice, with the fields enclosed by brackets "[]"
1337 replaced with your own identifying information. (Don't include
1338 the brackets!) The text should be enclosed in the appropriate
1339 comment syntax for the file format. We also recommend that a
1340 file or class name and description of purpose be included on the
1341 same "printed page" as the copyright notice for easier
1342 identification within third-party archives.
1343
1344 Copyright 2006 Toomas Römer
1345
1346 Licensed under the Apache License, Version 2.0 (the "License");
1347 you may not use this file except in compliance with the License.
1348 You may obtain a copy of the License at
1349
1350 http://www.apache.org/licenses/LICENSE-2.0
1351
1352 Unless required by applicable law or agreed to in writing, software
1353 distributed under the License is distributed on an "AS IS" BASIS,
1354 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1355 See the License for the specific language governing permissions and
1356 limitations under the License.
1357
1358******************************************************************************/