2 This program is free software; you can redistribute it and/or modify
3 it under the terms of the GNU General Public License as published by
4 the Free Software Foundation; either version 2 of the License, or
5 (at your option) any later version.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 Feb 9 1996 - rewritten - DAV
25 const char *colorstr[] = {"", "[black] ", "[white] "};
26 const char *adjustr[] = {"", " (adjourned)"};
28 static void prepare_match(int g,int wt,int bt,int winc,int binc,int wp, int bp,int rated)
31 wt = wt * 60; /* To Seconds */
33 game_globals.garray[g].white = wp;
34 game_globals.garray[g].black = bp;
35 strcpy(game_globals.garray[g].white_name, player_globals.parray[wp].name);
36 strcpy(game_globals.garray[g].black_name, player_globals.parray[bp].name);
37 game_globals.garray[g].status = GAME_ACTIVE;
38 if ((game_globals.garray[g].type == TYPE_UNTIMED) || (game_globals.garray[g].type == TYPE_NONSTANDARD))
39 game_globals.garray[g].rated = 0;
41 game_globals.garray[g].rated = rated;
42 game_globals.garray[g].private = BoolCheckPFlag(wp, PFLAG_PRIVATE)
43 || BoolCheckPFlag(bp, PFLAG_PRIVATE);
44 game_globals.garray[g].white = wp;
45 if (game_globals.garray[g].type == TYPE_BLITZ) {
46 game_globals.garray[g].white_rating = player_globals.parray[wp].b_stats.rating;
47 game_globals.garray[g].black_rating = player_globals.parray[bp].b_stats.rating;
48 } else if (game_globals.garray[g].type == TYPE_WILD) {
49 game_globals.garray[g].white_rating = player_globals.parray[wp].w_stats.rating;
50 game_globals.garray[g].black_rating = player_globals.parray[bp].w_stats.rating;
51 } else if (game_globals.garray[g].type == TYPE_LIGHT) {
52 game_globals.garray[g].white_rating = player_globals.parray[wp].l_stats.rating;
53 game_globals.garray[g].black_rating = player_globals.parray[bp].l_stats.rating;
54 } else if (game_globals.garray[g].type == TYPE_BUGHOUSE) {
55 game_globals.garray[g].white_rating = player_globals.parray[wp].bug_stats.rating;
56 game_globals.garray[g].black_rating = player_globals.parray[bp].bug_stats.rating;
58 game_globals.garray[g].white_rating = player_globals.parray[wp].s_stats.rating;
59 game_globals.garray[g].black_rating = player_globals.parray[bp].s_stats.rating;
62 game_globals.garray[g].game_state.gameNum = g;
64 game_globals.garray[g].wTime = wt * 10;
65 game_globals.garray[g].wInitTime = wt * 10;
66 game_globals.garray[g].wIncrement = winc * 10;
67 game_globals.garray[g].bTime = bt * 10;
69 if (game_globals.garray[g].type != TYPE_UNTIMED) {
71 game_globals.garray[g].wTime = 100;
73 game_globals.garray[g].bTime = 100;
74 } /* 0 x games start with 10 seconds */
76 game_globals.garray[g].wRealTime = game_globals.garray[g].wTime * 100;
77 game_globals.garray[g].bRealTime = game_globals.garray[g].bTime * 100;
78 game_globals.garray[g].wTimeWhenReceivedMove = 0;
79 game_globals.garray[g].bTimeWhenReceivedMove = 0;
81 game_globals.garray[g].bInitTime = bt * 10;
82 game_globals.garray[g].bIncrement = binc * 10;
84 if (game_globals.garray[g].game_state.onMove == BLACK) { /* Start with black */
85 game_globals.garray[g].numHalfMoves = 1;
86 game_globals.garray[g].moveListSize = 1;
87 game_globals.garray[g].moveList = (struct move_t *) malloc(sizeof(struct move_t));
88 game_globals.garray[g].moveList[0].fromFile = -1;
89 game_globals.garray[g].moveList[0].fromRank = -1;
90 game_globals.garray[g].moveList[0].toFile = -1;
91 game_globals.garray[g].moveList[0].toRank = -1;
92 game_globals.garray[g].moveList[0].color = WHITE;
93 strcpy(game_globals.garray[g].moveList[0].moveString, "NONE");
94 strcpy(game_globals.garray[g].moveList[0].algString, "NONE");
96 game_globals.garray[g].numHalfMoves = 0;
97 game_globals.garray[g].moveListSize = 0;
98 game_globals.garray[g].moveList = NULL;
101 game_globals.garray[g].timeOfStart = tenth_secs();
102 game_globals.garray[g].startTime = tenth_secs();
103 game_globals.garray[g].lastMoveTime = game_globals.garray[g].startTime;
104 game_globals.garray[g].lastDecTime = game_globals.garray[g].startTime;
105 game_globals.garray[g].clockStopped = 0;
109 static void pick_colors(int* wp,int* bp,int white,int wt,int bt,int winc,
116 reverse = 1; /* did challenger ask for black? */
118 } else if (white == -1) { /* unknown */
120 if ((wt == bt) && (winc == binc)) { /* if diff times challenger is white */
122 if (CheckPFlag(*wp, PFLAG_LASTBLACK)==CheckPFlag(*bp, PFLAG_LASTBLACK)) {
123 if ((player_globals.parray[*wp].num_white - player_globals.parray[*wp].num_black) >
124 (player_globals.parray[*bp].num_white - player_globals.parray[*bp].num_black))
125 reverse = 1; /* whose played the most extra whites gets black */
127 } else if (!CheckPFlag(*wp, PFLAG_LASTBLACK))
140 static void output_match_messages(int wp,int bp,int g, char* mess)
144 int avail_printed = 0;
145 char notavail_white[200];
146 char notavail_black[200];
150 notavail_white[0] = '\0';
151 notavail_black[0] = '\0';
153 asprintf(&outStr,"\nCreating: %s (%d) %s (%d) %s %s %d %d\n",
154 player_globals.parray[wp].name,
155 game_globals.garray[g].white_rating,
156 player_globals.parray[bp].name,
157 game_globals.garray[g].black_rating,
158 rstr[game_globals.garray[g].rated],
159 //bstr[game_globals.garray[g].type],
160 game_globals.garray[g].variant,
161 game_globals.garray[g].wInitTime/600,
162 game_globals.garray[g].wIncrement/10);
163 pprintf(wp, "%s", outStr);
164 pprintf(bp, "%s", outStr);
167 asprintf(&outStr, "\n{Game %d (%s vs. %s) %s %s %s match.}\n",
168 g + 1, player_globals.parray[wp].name,
169 player_globals.parray[bp].name,
171 rstr[game_globals.garray[g].rated],
172 //bstr[game_globals.garray[g].type]);
173 game_globals.garray[g].variant);
174 pprintf(wp, "%s", outStr);
175 pprintf(bp, "%s", outStr);
177 if (!(player_num_active_boards(wp)) && CheckPFlag(wp, PFLAG_OPEN))
178 /* open may be 0 if a simul */
179 getnotavailmess(wp,notavail_white);
180 if (CheckPFlag(bp, PFLAG_OPEN))
181 getnotavailmess(bp,notavail_black);
182 for (p = 0; p < player_globals.p_num; p++) {
183 struct player *pp = &player_globals.parray[p];
187 if ((p == wp) || (p == bp))
189 if (pp->status != PLAYER_PROMPT)
191 if (CheckPFlag(p, PFLAG_GIN)) {
192 pprintf(p, "%s", outStr);
195 gnw = in_list(p, L_GNOTIFY, player_globals.parray[wp].login);
196 gnb = in_list(p, L_GNOTIFY, player_globals.parray[bp].login);
198 pprintf(p, "\nGame notification: ");
201 pprintf_highlight(p, player_globals.parray[wp].name);
203 pprintf(p, player_globals.parray[wp].name);
205 pprintf(p, " (%s) vs. ",
206 ratstr(GetRating(&player_globals.parray[wp], game_globals.garray[g].type)));
209 pprintf_highlight(p, player_globals.parray[bp].name);
211 pprintf(p, player_globals.parray[bp].name);
212 pprintf(p, " (%s) %s %s %d %d: Game %d\n",
213 ratstr(GetRating(&player_globals.parray[bp], game_globals.garray[g].type)),
214 rstr[game_globals.garray[g].rated], bstr[game_globals.garray[g].type],
215 game_globals.garray[g].wInitTime/600, game_globals.garray[g].wIncrement/10, g+1);
220 if (CheckPFlag(p, PFLAG_AVAIL) && CheckPFlag(p, PFLAG_OPEN) && (pp->game < 0) &&
221 (CheckPFlag(wp, PFLAG_OPEN) || CheckPFlag(bp, PFLAG_OPEN))) {
223 if (((player_globals.parray[wp].b_stats.rating <= pp->availmax) &&
224 (player_globals.parray[wp].b_stats.rating >= pp->availmin)) ||
226 pprintf (p,"\n%s",notavail_white);
230 if (((player_globals.parray[bp].b_stats.rating <= pp->availmax) &&
231 (player_globals.parray[bp].b_stats.rating >= pp->availmin)) ||
233 pprintf (p,"\n%s",notavail_black);
241 } /* was black or white open originally (for simuls) */
251 int create_new_match(int g, int white_player, int black_player,
252 int wt, int winc, int bt, int binc,
253 int rated, char *category, char *board,
254 int white, int simul)
257 remove_request(white_player, black_player, -PEND_PARTNER);
259 pick_colors(&white_player,&black_player,white,wt,bt,winc,binc);
261 decline_withdraw_offers(white_player,-1, PEND_MATCH,DO_WITHDRAW | DO_DECLINE);
262 decline_withdraw_offers(black_player,-1, PEND_MATCH,DO_WITHDRAW | DO_DECLINE);
263 decline_withdraw_offers(black_player,-1, PEND_SIMUL,DO_WITHDRAW | DO_DECLINE);
265 decline_withdraw_offers(white_player, -1, PEND_SIMUL, DO_WITHDRAW);
267 decline_withdraw_offers(white_player, -1, PEND_SIMUL,
268 DO_WITHDRAW | DO_DECLINE);
270 game_globals.garray[g].FENstartPos[0] = 0; // [HGM] new shuffle
271 if (board_init(g,&game_globals.garray[g].game_state, category, board)) {
272 pprintf(white_player, "PROBLEM LOADING BOARD. Game Aborted.\n");
273 pprintf(black_player, "PROBLEM LOADING BOARD. Game Aborted.\n");
274 d_printf( "CHESSD: PROBLEM LOADING BOARD %s %s. Game Aborted.\n",
281 game_globals.garray[g].type = TYPE_UNTIMED;
283 game_globals.garray[g].type = game_isblitz(wt, winc, bt, binc, category, board);
285 if(category && category[0]) { // [HGM] set variant string from directory for games loaded from file
286 if(!strcmp(category, "wild") && board)
287 sprintf(game_globals.garray[g].variant, "%s/%s", category, board);
289 strcpy(game_globals.garray[g].variant, category);
292 strcpy(game_globals.garray[g].variant, bstr[game_globals.garray[g].type]);
294 prepare_match(g,wt,bt,winc,binc,white_player,black_player,rated);
296 output_match_messages(white_player,black_player,g, "Creating");
298 player_globals.parray[white_player].game = g;
299 player_globals.parray[white_player].opponent = black_player;
300 player_globals.parray[white_player].side = WHITE;
301 player_globals.parray[white_player].promote = QUEEN;
302 player_globals.parray[black_player].game = g;
303 player_globals.parray[black_player].opponent = white_player;
304 player_globals.parray[black_player].side = BLACK;
305 player_globals.parray[black_player].promote = QUEEN;
307 gics_globals.userstat.games++;
309 /* obey any 'follow' lists */
310 follow_start(white_player,black_player);
315 int accept_match(struct pending *pend, int p, int p1)
317 struct player *pp = &player_globals.parray[p];
318 int wt, winc, bt, binc, rated, white;
319 char category[50], board[50];
321 int bh = 0, partner = 0, pp1 = 0, g1, g2;
323 unobserveAll(p); /* stop observing when match starts */
331 strcpy (category, pend->category);
332 strcpy (board, pend->board_type);
333 white = (pend->seek_color == -1) ? -1 : 1 - pend->seek_color;
335 pprintf(p, "You accept the challenge of %s.\n", player_globals.parray[p1].name);
336 pprintf_prompt(p1, "\n%s accepts your challenge.\n", pp->name);
339 delete_pending(pend);
344 pend_join_match (p,p1);
346 if (game_isblitz(wt, winc, bt, binc, category, board) == TYPE_BUGHOUSE) {
349 if ((partner = pp->partner) >= 0 &&
350 (pp1 = player_globals.parray[p1].partner) >= 0) {
351 unobserveAll(partner); /* stop observing when match starts */
354 pprintf(partner, "\nYour partner accepts the challenge of %s.\n", player_globals.parray[p1].name);
355 pprintf(pp1, "\n%s accepts your partner's challenge.\n", pp->name);
357 pend_join_match (partner,pp1);
363 g1 = game_new(); /* create a game structure */
365 sprintf(tmp, "There was a problem creating the new match.\n");
367 pprintf_prompt(p1, tmp);
370 if (game_read(g1, p1, p) >= 0) {
375 pp = &player_globals.parray[p];
376 } else if (game_read(g1, p, p1) < 0) { /* so no adjourned game */
377 if (create_new_match(g1,p, p1, wt, winc, bt, binc, rated, category, board, white,0) == COM_FAILED)
380 /* create first game */
382 if (bh) { /* do bughouse creation */
384 white = (pp->side == WHITE ? 0 : 1);
386 if ((g2 < 0) || (create_new_match(g2,partner, pp1, wt, winc, bt, binc, rated, category, board,white,0) == COM_FAILED)) {
387 sprintf(tmp, "There was a problem creating the new match.\n");
388 pprintf_prompt(partner, tmp);
389 pprintf_prompt(pp1, tmp);
390 sprintf(tmp, "There was a problem creating your partner's match.\n");
391 game_remove(g1); /* abort first game */
395 game_globals.garray[g1].link = g2; /* link the games */
396 game_globals.garray[g2].link = g1;
398 sprintf(tmp, "\nYour partner is playing game %d (%s vs. %s).\n",
399 g2 + 1, game_globals.garray[g2].white_name, game_globals.garray[g2].black_name);
401 pprintf_prompt(p1, tmp);
403 sprintf(tmp, "\nYour partner is playing game %d (%s vs. %s).\n",
404 g1 + 1, game_globals.garray[g1].white_name, game_globals.garray[g1].black_name);
405 pprintf_prompt(partner, tmp);
406 pprintf_prompt(pp1, tmp);
411 /* resume adjourned game */
413 game_delete(p, p1); /* remove the game from disk */
415 sprintf(tmp, "{Game %d (%s vs. %s) Continuing %s %s match.}\n",
416 g1+1, pp->name, player_globals.parray[p1].name,
417 rstr[game_globals.garray[g1].rated], bstr[game_globals.garray[g1].type]);
420 output_match_messages(p, p1, g1, "Continuing");
422 game_globals.garray[g1].white = p;
423 game_globals.garray[g1].black = p1;
424 game_globals.garray[g1].status = GAME_ACTIVE;
425 game_globals.garray[g1].result = END_NOTENDED;
426 game_globals.garray[g1].startTime = tenth_secs();
427 game_globals.garray[g1].lastMoveTime = game_globals.garray[g1].startTime;
428 game_globals.garray[g1].lastDecTime = game_globals.garray[g1].startTime;
432 player_globals.parray[p1].game = g1;
433 player_globals.parray[p1].opponent = p;
434 player_globals.parray[p1].side = BLACK;
438 /* obey any 'follow' lists */
444 /* board and category are initially empty strings */
445 int parse_match_string(int p, int* wt,int* bt,int* winc,int* binc,
446 int* white,int* rated,char* category,
447 char* board, char* mstring)
454 while (!confused && (sscanf(mstring, " %99s", parsebuf) == 1)) {
455 mstring = eatword(eatwhite(mstring));
457 if ((category[0] != '\0') && (board[0] == '\0') && !bughouse)
458 strcpy(board, parsebuf);
459 else if (isdigit(*parsebuf)) {
460 if ((numba = atoi(parsebuf)) < 0) {
461 pprintf(p, "You can't specify negative time controls.\n");
463 } else if (numba > 999) {
464 pprintf(p, "You can't specify time or inc above 999.\n");
466 } else if (*wt == -1) {
468 } else if (*winc == -1) {
470 } else if (*bt == -1) {
472 } else if (*binc == -1) {
477 } else if ((!strcmp("rated", parsebuf)) || (!strcmp("r",parsebuf))) {
482 } else if ((!strcmp("unrated", parsebuf)) || (!strcmp("u",parsebuf))) {
487 } else if (!strcmp("white", parsebuf) || !strcmp ("w", parsebuf)) {
492 } else if (!strcmp("black", parsebuf) || !strcmp ("b", parsebuf)) {
498 } else if (category[0] == '\0') {
499 if ((parsebuf[0] == 'w') && (isdigit(*(parsebuf + 1)))) {
500 strcpy (category, "wild");
501 strcpy (board, parsebuf+1);
503 strcpy(category,parsebuf);
504 if (!strncmp("bughouse",category, strlen(category))
505 && strlen(category) >= 3 || !strcmp("bh", category)) {
506 strcpy(category, "bughouse");
509 // [HGM] allow some shortcuts for variant names
510 if(!strcmp("bh", category)) {
511 strcpy(category, "bughouse");
513 if(!strcmp("zh", category)) {
514 strcpy(category, "crazyhouse");
516 if(!strcmp("fr", category)) {
517 strcpy(category, "fischerandom");
519 if(!strcmp("sj", category)) {
520 strcpy(category, "shatranj");
522 if(!strcmp("gc", category)) {
523 strcpy(category, "gothic");
525 if(!strcmp("ca", category)) {
526 strcpy(category, "capablanca");
528 if(!strcmp("cr", category)) {
529 strcpy(category, "caparandom");
531 if(!strcmp("su", category)) {
532 strcpy(category, "super");
534 if(!strcmp("sc", category)) {
535 strcpy(category, "seirawan");
537 if(!strcmp("sg", category)) {
538 strcpy(category, "shogi");
540 if(!strcmp("km", category)) {
541 strcpy(category, "knightmate");
543 if(!strcmp("gr", category)) {
544 strcpy(category, "great");
546 if(!strcmp("sp", category)) {
547 strcpy(category, "spartan");
549 if(!strcmp("xq", category)) {
550 strcpy(category, "xiangqi");
558 pprintf(p, "Can't interpret %s in match command.\n", parsebuf);
561 if(category && (!board || !board[0]))
562 strcpy(board, "0"); // [HGM] variants: always provide default board
566 static void print_match_rating_info(int p,int p1,int type,int rated)
572 rating_sterr_delta(p1, p, type, time(0), RESULT_WIN, &win, &newsterr);
573 rating_sterr_delta(p1, p, type, time(0), RESULT_DRAW, &draw, &newsterr);
574 rating_sterr_delta(p1, p, type, time(0), RESULT_LOSS, &loss, &newsterr);
575 pprintf(p1, "Your %s rating will change: Win: %s%d, Draw: %s%d, Loss: %s%d\n",
577 (win >= 0) ? "+" : "", win,
578 (draw >= 0) ? "+" : "", draw,
579 (loss >= 0) ? "+" : "", loss);
580 pprintf(p1, "Your new RD will be %5.1f\n", newsterr);
582 rating_sterr_delta(p, p1, type, time(0), RESULT_WIN, &win, &newsterr);
583 rating_sterr_delta(p, p1, type, time(0), RESULT_DRAW, &draw, &newsterr);
584 rating_sterr_delta(p, p1, type, time(0), RESULT_LOSS, &loss, &newsterr);
585 pprintf(p, "Your %s rating will change: Win: %s%d, Draw: %s%d, Loss: %s%d\n",
587 (win >= 0) ? "+" : "", win,
588 (draw >= 0) ? "+" : "", draw,
589 (loss >= 0) ? "+" : "", loss);
590 pprintf(p, "Your new RD will be %5.1f\n", newsterr);
594 static void check_lists_match(int p,int p1)
596 struct player *pp = &player_globals.parray[p];
597 if (in_list(p, L_COMPUTER, pp->name)) {
598 pprintf(p1, "--** %s is a ", pp->name);
599 pprintf_highlight(p1, "computer");
600 pprintf(p1, " **--\n");
602 if (in_list(p, L_COMPUTER, player_globals.parray[p1].name)) {
603 pprintf(p, "--** %s is a ", player_globals.parray[p1].name);
604 pprintf_highlight(p, "computer");
605 pprintf(p, " **--\n");
607 if (in_list(p, L_ABUSER, pp->name)) {
608 pprintf(p1, "--** %s is in the ", pp->name);
609 pprintf_highlight(p1, "abuser");
610 pprintf(p1, " list **--\n");
612 if (in_list(p, L_ABUSER, player_globals.parray[p1].name)) {
613 pprintf(p, "--** %s is in the ", player_globals.parray[p1].name);
614 pprintf_highlight(p, "abuser");
615 pprintf(p, " list **--\n");
619 int com_match(int p, param_list param)
621 struct player *pp = &player_globals.parray[p];
622 int adjourned; /* adjourned game? */
623 int g; /* more adjourned game junk */
625 int bh = 0, partner = 0, pp1 = 0;
626 struct pending* pendfrom;
627 struct pending* pendto;
628 struct pending* pend;
629 int wt = -1; /* white start time */
630 int winc = -1; /* white increment */
631 int bt = -1; /* black start time */
632 int binc = -1; /* black increment */
633 int rated = -1; /* 1 = rated, 0 = unrated */
634 int white = -1; /* 1 = want white, 0 = want black */
635 char category[100], board[100];
636 textlist *clauses = NULL;
642 if ((pp->game >= 0) && ((game_globals.garray[pp->game].status == GAME_EXAMINE)
643 || (game_globals.garray[pp->game].status == GAME_SETUP))) {
645 pprintf(p, "You can't challenge while you are examining a game.\n");
650 pprintf(p, "You can't challenge while you are playing a game.\n");
654 stolower(param[0].val.word);
655 p1 = player_find_part_login(param[0].val.word);
657 pprintf(p, "No user named \"%s\" is logged in.\n", param[0].val.word);
661 if (p1 == p) { /* Allowing to match yourself to enter
663 ExamineScratch (p, param, 0);
667 if (!CheckPFlag(p1, PFLAG_OPEN)) {
668 pprintf(p, "Player \"%s\" is not open to match requests.\n", player_globals.parray[p1].name);
672 if (player_globals.parray[p1].game >= 0) {
673 pprintf(p, "Player \"%s\" is involved in another game.\n", player_globals.parray[p1].name); return COM_OK;
676 if (CheckPFlag(p, PFLAG_TOURNEY) && !CheckPFlag(p1, PFLAG_TOURNEY)) {
677 pprintf(p, "You may only match players with their tournament variable set.\n");
681 if (!CheckPFlag(p, PFLAG_TOURNEY) && CheckPFlag(p1, PFLAG_TOURNEY)) {
682 pprintf(p, "%s is in a tournament, and cannot accept other challenges.\n", player_globals.parray[p1].name);
686 if (!CheckPFlag(p, PFLAG_OPEN)) {
687 PFlagON(p, PFLAG_OPEN);
688 pprintf(p, "Setting you open for matches.\n");
692 /* look for an adjourned game between p and p1 */
694 adjourned = (game_read(g, p, p1) >= 0) || (game_read(g, p1, p) >= 0);
697 type = game_globals.garray[g].type;
698 wt = game_globals.garray[g].wInitTime / 600;
699 bt = game_globals.garray[g].bInitTime / 600;
700 winc = game_globals.garray[g].wIncrement / 10;
701 binc = game_globals.garray[g].bIncrement / 10;
702 rated = game_globals.garray[g].rated;
703 strcpy(category, game_globals.garray[g].variant);
704 if(q = strchr(category, '/')) {
705 *q = 0; strcpy(board, q+1);
706 } else strcpy(board, "0");
710 pendto = find_pend(p, p1, PEND_MATCH);
712 pendfrom = find_pend(p1, p, PEND_MATCH);
715 if (in_list(p1, L_NOPLAY, pp->login)) {
716 pprintf(p, "You are on %s's noplay list.\n", player_globals.parray[p1].name);
719 if (player_censored(p1, p)) {
720 pprintf(p, "Player \"%s\" is censoring you.\n", player_globals.parray[p1].name);
723 if (player_censored(p, p1)) {
724 pprintf(p, "You are censoring \"%s\".\n", player_globals.parray[p1].name);
728 if (param[1].type != TYPE_NULL) {
729 if (!parse_match_string(p, &wt,&bt,&winc,&binc,&white,&rated,category,
730 board,param[1].val.string))
731 return COM_OK; /* couldn't parse */
735 rated = BoolCheckPFlag(p, PFLAG_RATED);
736 if (!CheckPFlag(p, PFLAG_REG) || !CheckPFlag(p1, PFLAG_REG))
740 winc = (wt == -1) ? pp->d_inc : 0; /* match 5 == match 5 0 */
752 if (!board[0] && strcmp(category,"bughouse")) {
753 pprintf(p, "You must specify a board and a category.\n");
756 } else if (board[0]) { /* not bughouse */
757 char fname[MAX_FILENAME_SIZE];
759 sprintf(fname, "%s/%s/%s", BOARD_DIR, category, board);
760 if (!file_exists(fname)) {
761 pprintf(p, "No such category/board: %s/%s\n", category, board);
766 type = game_isblitz(wt, winc, bt, binc, category, board);
768 if (!strcmp(category, "bughouse")) {
769 type = TYPE_BUGHOUSE;
770 if (rated && pp->partner >= 0 && player_globals.parray[p1].partner >= 0) {
771 if (!CheckPFlag(pp->partner, PFLAG_REG)
772 || !CheckPFlag(player_globals.parray[p1].partner, PFLAG_REG))
776 if (rated && (type == TYPE_NONSTANDARD)) {
777 pprintf(p, "Game is non-standard - reverting to unrated\n");
780 if (rated && (type == TYPE_UNTIMED)) {
781 pprintf(p, "Game is untimed - reverting to unrated\n");
784 if ((pendfrom == NULL) && !CheckPFlag(p1, PFLAG_ROPEN)
785 && (rated != BoolCheckPFlag(p1, PFLAG_RATED))) {
786 pprintf(p, "%s only wants to play %s games.\n", player_globals.parray[p1].name,
788 pprintf_highlight(p1, "Ignoring");
789 pprintf(p1, " %srated match request from %s.\n",
790 (rated ? "" : "un"), pp->name);
794 /* Now check formula. */
796 && !GameMatchesFormula(p,p1, wt,winc,bt,binc, rated, type, &clauses)) {
797 pprintf(p, "Match request does not fit formula for %s:\n",
798 player_globals.parray[p1].name);
799 pprintf(p, "%s's formula: %s\n", player_globals.parray[p1].name, player_globals.parray[p1].formula);
800 ShowClauses (p, p1, clauses);
801 ClearTextList(clauses);
802 pprintf_highlight(p1, "Ignoring");
803 pprintf_prompt(p1, " (formula): %s (%d) %s (%d) %s.\n",
805 GetRating(&player_globals.parray[p], type),
806 player_globals.parray[p1].name,
807 GetRating(&player_globals.parray[p1], type),
808 game_str(rated, wt * 60, winc, bt * 60, binc, category, board));
812 if (type == TYPE_BUGHOUSE) {
814 partner = pp->partner;
815 pp1 = player_globals.parray[p1].partner;
818 pprintf(p, "You have no partner for bughouse.\n");
822 pprintf(p, "Your opponent has no partner for bughouse.\n");
825 if (partner == pp1) { /* should be an impossible case - DAV */
826 pprintf(p, "You and your opponent both chose the same partner!\n");
829 if (partner == p1 || pp1 == p) {
830 pprintf(p, "You and your opponent can't choose each other as partners!\n");
833 if (player_globals.parray[partner].partner != p) { /* another impossible case - DAV */
834 pprintf(p, "Your partner hasn't chosen you as his partner!\n");
837 if (player_globals.parray[pp1].partner != p1) { /* another impossible case - DAV */
838 pprintf(p, "Your opponent's partner hasn't chosen your opponent as his partner!\n");
841 if (!CheckPFlag(partner, PFLAG_OPEN) || player_globals.parray[partner].game >= 0) {
842 pprintf(p, "Your partner isn't open to play right now.\n");
845 if (!CheckPFlag(pp1, PFLAG_OPEN) || player_globals.parray[pp1].game >= 0) {
846 pprintf(p, "Your opponent's partner isn't open to play right now.\n");
850 /* Bypass NOPLAY lists, censored lists, ratedness, privacy, and formula for now */
851 /* Active challenger/ee will determine these. */
853 /* Ok match offer will be made */
855 } /* adjourned games shouldn't have to worry
857 /* keep incase of adjourned bughouse in future*/
859 if (pendto != NULL) {
860 pprintf(p, "Updating offer already made to \"%s\".\n", player_globals.parray[p1].name);
863 if (pendfrom != NULL) {
864 if (pendto != NULL) {
865 pprintf(p, "Pending list error!.\n");
866 d_printf( "CHESSD: This shouldn't happen. You can't have a match pending from and to the same person.\n");
870 if (adjourned || ((wt == pendfrom->btime) &&
871 (winc == pendfrom->binc) &&
872 (bt == pendfrom->wtime) &&
873 (binc == pendfrom->winc) &&
874 (rated == pendfrom->rated) &&
875 ((white == -1) || (white + pendfrom->seek_color == 1)) &&
876 (!strcmp(category, pendfrom->category)) &&
877 (!strcmp(board, pendfrom->board_type)))) {
878 /* Identical match, should accept! */
879 accept_match(pendfrom,p, p1);
883 delete_pending(pendfrom);
888 pend = add_pending(p,p1,PEND_MATCH);
897 pend->seek_color = white;
898 pend->game_type = type;
899 pend->category = strdup(category);
900 pend->board_type = strdup (board);
902 if (pendfrom != NULL) {
903 pprintf(p, "Declining offer from %s and offering new match parameters.\n", player_globals.parray[p1].name);
904 pprintf(p1, "\n%s declines your match offer a match with these parameters:", pp->name);
907 if (pendto != NULL) {
908 pprintf(p, "Updating match request to: ");
909 pprintf(p1, "\n%s updates the match request.\n", pp->name);
911 pprintf(p, "Issuing: ");
915 pprintf(p, "%s (%s) %s", pp->name,
916 ratstrii(GetRating(&player_globals.parray[p], type), p),
917 colorstr[white + 1]);
918 pprintf_highlight(p, "%s", player_globals.parray[p1].name);
919 pprintf(p, " (%s) %s%s.\n",
920 ratstrii(GetRating(&player_globals.parray[p1], type), p1),
921 game_str(rated, wt * 60, winc, bt * 60, binc, category, board),
923 pprintf(p1, "Challenge: ");
924 pprintf_highlight(p1, "%s", pp->name);
925 pprintf(p1, " (%s) %s",
926 ratstrii(GetRating(&player_globals.parray[p], type), p),
927 colorstr[white + 1]);
928 pprintf(p1, "%s (%s) %s%s.\n", player_globals.parray[p1].name,
929 ratstrii(GetRating(&player_globals.parray[p1], type), p1),
930 game_str(rated, wt * 60, winc, bt * 60, binc, category, board),
936 pprintf(partner, "\nYour bughouse partner issuing %s (%s) %s",
937 pp->name, ratstrii(GetRating(&player_globals.parray[p], type), p),
938 colorstr[white + 1]);
939 pprintf_highlight(partner, "%s", player_globals.parray[p1].name);
940 pprintf(partner, " (%s) %s.\n",
941 ratstrii(GetRating(&player_globals.parray[p1], type), p1),
942 game_str(rated, wt * 60, winc, bt * 60, binc, category, board));
943 pprintf(partner, "Your game would be ");
944 pprintf_highlight(partner, "%s", player_globals.parray[pp1].name);
945 pprintf_prompt(partner, " (%s) %s%s (%s) %s.\n",
946 ratstrii(GetRating(&player_globals.parray[pp1], type), pp1),
947 colorstr[white + 1], player_globals.parray[partner].name,
948 ratstrii(GetRating(&player_globals.parray[partner], type), partner),
949 game_str(rated, wt * 60, winc, bt * 60, binc, category, board));
952 pprintf(pp1, "\nYour bughouse partner was challenged ");
953 pprintf_highlight(pp1, "%s", pp->name);
954 pprintf(pp1, " (%s) %s", ratstrii(GetRating(&player_globals.parray[p], type), p),
955 colorstr[white + 1]);
956 pprintf(pp1, "%s (%s) %s.\n", player_globals.parray[p1].name,
957 ratstrii(GetRating(&player_globals.parray[p1], type), p1),
958 game_str(rated, wt * 60, winc, bt * 60, binc, category, board));
959 pprintf(pp1, "Your game would be %s (%s) %s", player_globals.parray[pp1].name,
960 ratstrii(GetRating(&player_globals.parray[pp1], type), pp1),
961 colorstr[white + 1]);
962 pprintf_highlight(pp1, "%s", player_globals.parray[partner].name);
963 pprintf_prompt(pp1, " (%s) %s.\n",
964 ratstrii(GetRating(&player_globals.parray[partner], type), partner),
965 game_str(rated, wt * 60, winc, bt * 60, binc, category, board));
969 check_lists_match (p,p1);
971 print_match_rating_info (p,p1,type,rated);
973 pprintf_prompt(p1, "You can \"accept\" or \"decline\", or propose different parameters.\n");
980 rmatch is used by mamer to start matches in tournaments
982 int com_rmatch(int p, param_list param)
984 struct player *pp = &player_globals.parray[p];
987 if (!in_list(p, L_TD, pp->name)) {
988 pprintf(p, "Only TD programs are allowed to use this command.\n");
992 if ((p1 = player_find_bylogin(param[0].val.word)) < 0 ||
993 !CheckPFlag(p1, PFLAG_REG)) {
994 /* can't rmatch this user ... */
998 if ((p2 = player_find_bylogin(param[1].val.word)) < 0 ||
999 !CheckPFlag(p2, PFLAG_REG)) {
1000 /* can't rmatch this user ... */
1004 return pcommand(p1, "match %s %s", param[1].val.word, param[2].val.string);