2 Copyright (c) 1993 Richard V. Nash.
3 Copyright (c) 2000 Dan Papasian
4 Copyright (C) Andrew Tridgell 2002
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 /*Let users know that someone is available (format the message)*/
24 static void getavailmess(int p, char* message)
26 struct player *pp = &player_globals.parray[p];
30 AddPlayerLists(p,titles);
31 sprintf (message,"%s%s Blitz (%s), Std (%s), Wild (%s), Light(%s), Bug(%s)\n"
32 " is now available for matches.",
34 ratstrii(pp->b_stats.rating, p),
35 ratstrii(pp->s_stats.rating, p),
36 ratstrii(pp->w_stats.rating, p),
37 ratstrii(pp->l_stats.rating, p),
38 ratstrii(pp->bug_stats.rating, p));
41 void getnotavailmess(int p, char* message)
43 struct player *pp = &player_globals.parray[p];
47 AddPlayerLists(p,titles);
48 sprintf (message,"%s%s is no longer available for matches.",
52 void announce_avail(int p)
54 struct player *pp = &player_globals.parray[p];
57 if ((pp->game < 0) && (CheckPFlag(p, PFLAG_OPEN))) {
58 getavailmess (p,avail);
60 for (p1 = 0; p1 < player_globals.p_num; p1++) {
63 if (player_globals.parray[p1].status != PLAYER_PROMPT)
65 if (CheckPFlag(p1, PFLAG_AVAIL) && CheckPFlag(p1, PFLAG_OPEN)
66 && (player_globals.parray[p1].game < 0))
67 if (((pp->b_stats.rating <= player_globals.parray[p1].availmax) && (pp->b_stats.rating >= player_globals.parray[p1].availmin)) || (!player_globals.parray[p1].availmax))
68 pprintf_prompt (p1,"\n%s\n",avail);
73 void announce_notavail(int p)
75 struct player *pp = &player_globals.parray[p];
79 getnotavailmess (p,avail);
81 for (p1 = 0; p1 < player_globals.p_num; p1++) {
84 if (player_globals.parray[p1].status != PLAYER_PROMPT)
86 if (CheckPFlag(p1, PFLAG_AVAIL) && CheckPFlag(p1, PFLAG_OPEN)
87 && (player_globals.parray[p1].game < 0))
88 if (((pp->b_stats.rating <= player_globals.parray[p1].availmax) && (pp->b_stats.rating >= player_globals.parray[p1].availmin)) || (!player_globals.parray[p1].availmax))
89 pprintf_prompt (p1,"\n%s\n",avail);
93 void game_ended(int g, int winner, int why)
95 struct game *gg = &game_globals.garray[g];
97 char avail_black[200]; /* for announcing white/black avail */
98 char avail_white[200];
99 char avail_bugwhite[200];
100 char avail_bugblack[200];
109 char *NameOfWinner, *NameOfLoser;
110 int beingplayed = 0; /* i.e. it wasn't loaded for adjudication */
113 avail_white[0] = '\0';
114 avail_black[0] = '\0';
115 avail_bugwhite[0] = '\0';
116 avail_bugblack[0] = '\0';
118 beingplayed = (player_globals.parray[gg->black].game == g);
120 sprintf(outstr, "\n{Game %d (%s vs. %s) ", g + 1,
121 player_globals.parray[gg->white].name,
122 player_globals.parray[gg->black].name);
125 if (winner == WHITE) {
126 whiteResult = RESULT_WIN;
127 strcpy(winSymbol, "1-0");
128 NameOfWinner = player_globals.parray[gg->white].name;
129 NameOfLoser = player_globals.parray[gg->black].name;
131 whiteResult = RESULT_LOSS;
132 strcpy(winSymbol, "0-1");
133 NameOfWinner = player_globals.parray[gg->black].name;
134 NameOfLoser = player_globals.parray[gg->white].name;
138 sprintf(tmp, "%s checkmated} %s", NameOfLoser, winSymbol);
139 strcpy(EndSymbol, "Mat");
143 sprintf(tmp, "%s resigns} %s", NameOfLoser, winSymbol);
144 strcpy(EndSymbol, "Res");
148 sprintf(tmp, "%s forfeits on time} %s", NameOfLoser, winSymbol);
149 strcpy(EndSymbol, "Fla");
153 sprintf(tmp, "Game drawn by stalemate} 1/2-1/2");
155 strcpy(EndSymbol, "Sta");
157 whiteResult = RESULT_DRAW;
160 sprintf(tmp, "Game drawn by mutual agreement} 1/2-1/2");
162 strcpy(EndSymbol, "Agr");
164 whiteResult = RESULT_DRAW;
167 sprintf(tmp, "Game drawn because both players ran out of time} 1/2-1/2");
169 strcpy(EndSymbol, "Fla");
171 whiteResult = RESULT_DRAW;
174 sprintf(tmp, "Game drawn by repetition} 1/2-1/2");
176 strcpy(EndSymbol, "Rep");
178 whiteResult = RESULT_DRAW;
181 sprintf(tmp, "Game drawn by the 50 move rule} 1/2-1/2");
183 strcpy(EndSymbol, "50");
185 whiteResult = RESULT_DRAW;
189 sprintf(tmp, "Bughouse game aborted.} *");
190 whiteResult = RESULT_ABORT;
192 sprintf(tmp, "Game adjourned by mutual agreement} *");
196 case END_LOSTCONNECTION:
197 sprintf(tmp, "%s lost connection; game ", NameOfWinner);
198 if (CheckPFlag(gg->white, PFLAG_REG)
199 && CheckPFlag(gg->black, PFLAG_REG)
201 sprintf(tmp, "adjourned} *");
204 sprintf(tmp, "aborted} *");
205 whiteResult = RESULT_ABORT;
208 sprintf(tmp, "Game aborted by mutual agreement} *");
209 whiteResult = RESULT_ABORT;
212 sprintf(tmp, "Game courtesyaborted by %s} *", NameOfWinner);
213 whiteResult = RESULT_ABORT;
215 case END_COURTESYADJOURN:
217 sprintf(tmp, "Bughouse game courtesyaborted by %s.} *", NameOfWinner);
218 whiteResult = RESULT_ABORT;
220 sprintf(tmp, "Game courtesyadjourned by %s} *", NameOfWinner);
225 /* Draw by insufficient material (e.g., lone K vs. lone K) */
226 sprintf(tmp, "Neither player has mating material} 1/2-1/2");
228 strcpy(EndSymbol, "NM ");
230 whiteResult = RESULT_DRAW;
232 case END_FLAGNOMATERIAL:
233 sprintf(tmp, "%s ran out of time and %s has no material to mate} 1/2-1/2",
234 NameOfLoser, NameOfWinner);
236 strcpy(EndSymbol, "TM ");
238 whiteResult = RESULT_DRAW;
241 sprintf(tmp, "%s wins by adjudication} %s", NameOfWinner, winSymbol);
242 strcpy(EndSymbol, "Adj");
246 sprintf(tmp, "Game drawn by adjudication} 1/2-1/2");
248 strcpy(EndSymbol, "Adj");
250 whiteResult = RESULT_DRAW;
253 sprintf(tmp, "Game aborted by adjudication} *");
254 whiteResult = RESULT_ABORT;
257 sprintf(tmp, "Hmm, the game ended and I don't know why} *");
262 if (CheckPFlag(gg->white, PFLAG_TOURNEY) &&
263 CheckPFlag(gg->black, PFLAG_TOURNEY)) {
264 /* mamer wants more info */
265 sprintf(tmp," [%d %d %d %d %d]",
266 gg->wInitTime/(60*10), gg->wIncrement/10, gg->rated, gg->private, (int)gg->type);
270 strcat(outstr, "\n");
272 if (gg->rated && rate_change && gg->type != TYPE_BUGHOUSE)
273 /* Adjust ratings; bughouse gets done later. */
274 rating_update(g, -1);
278 int avail_printed = 0;
280 pprintf_noformat(gg->white, outstr);
281 pprintf_noformat(gg->black, outstr);
285 gg->link = -1; /*IanO: avoids recursion */
286 if (gl >= 0 && game_globals.garray[gl].link >= 0) {
287 pprintf_noformat(game_globals.garray[gl].white, outstr);
288 pprintf_noformat(game_globals.garray[gl].black, outstr);
289 if (CheckPFlag(game_globals.garray[gl].white, PFLAG_OPEN)) {
290 getavailmess (game_globals.garray[gl].white, avail_bugwhite);
293 if (CheckPFlag(game_globals.garray[gl].black, PFLAG_OPEN)) {
294 getavailmess (game_globals.garray[gl].black, avail_bugblack);
297 if ((gg->rated) && (rate_change)) {
299 rating_update(g, gl);
301 game_ended(gl, CToggle(winner), why);
304 if ((player_num_active_boards(gg->white) <= 1) /* not a simul or */
305 && CheckPFlag(gg->white, PFLAG_OPEN)) { /* simul is over? */
306 getavailmess (gg->white,avail_white);
308 } else { /* Part of an ongoing simul! Let's shrink the array. */
312 if (CheckPFlag(gg->black, PFLAG_OPEN)) {
313 getavailmess (gg->black,avail_black);
317 for (p = 0; p < player_globals.p_num; p++) {
318 struct player *pp = &player_globals.parray[p];
319 if ((p == gg->white) || (p == gg->black))
321 if (pp->status != PLAYER_PROMPT)
324 if (CheckPFlag(p, PFLAG_GIN) || player_is_observe(p, g)) {
325 pprintf_noformat(p, outstr);
329 if (CheckPFlag(p, PFLAG_AVAIL) && (CheckPFlag(p, PFLAG_OPEN)) && (pp->game < 0) && (print_avail)) {
330 if (((player_globals.parray[gg->white].b_stats.rating <= pp->availmax) && (player_globals.parray[gg->white].b_stats.rating >= pp->availmin)) || (!pp->availmax)) {
331 pprintf (p,"\n%s",avail_white);
334 if (((player_globals.parray[gg->black].b_stats.rating <= pp->availmax) && (player_globals.parray[gg->black].b_stats.rating >= pp->availmin)) || (!pp->availmax)) {
335 pprintf (p,"\n%s",avail_black);
338 if (gl != -1) /* bughouse ? */ {
339 if (((player_globals.parray[game_globals.garray[gl].white].b_stats.rating <= pp->availmax) && (player_globals.parray[game_globals.garray[gl].white].b_stats.rating >= pp->availmin)) || (!pp->availmax)) {
340 pprintf (p,"\n%s",avail_bugwhite);
343 if (((player_globals.parray[game_globals.garray[gl].black].b_stats.rating <= pp->availmax) && (player_globals.parray[game_globals.garray[gl].black].b_stats.rating >= pp->availmin)) || (!pp->availmax)) {
344 pprintf (p,"\n%s",avail_bugblack);
361 if (!(gg->rated && rate_change)) {
362 pprintf(gg->white, "No ratings adjustment done.\n");
363 pprintf(gg->black, "No ratings adjustment done.\n");
367 if (rate_change && gl < 0)
368 game_write_complete(g, isDraw, EndSymbol);
369 /* Mail off the moves */
370 if (CheckPFlag(gg->white, PFLAG_AUTOMAIL)) {
371 pcommand(gg->white, "mailmoves");
373 if (CheckPFlag(gg->black, PFLAG_AUTOMAIL)) {
374 pcommand(gg->black, "mailmoves");
376 if (!((player_globals.parray[gg->white].simul_info != NULL) &&
377 (player_globals.parray[gg->white].simul_info->numBoards))) {
378 player_globals.parray[gg->white].num_white++;
379 PFlagOFF(gg->white, PFLAG_LASTBLACK);
380 player_globals.parray[gg->black].num_black++;
381 PFlagON(gg->black, PFLAG_LASTBLACK);
383 player_globals.parray[gg->white].last_opponent =
384 strdup(gg->black_name);
385 player_globals.parray[gg->black].last_opponent =
386 strdup(gg->white_name);
388 player_globals.parray[gg->white].game = -1;
389 player_globals.parray[gg->black].game = -1;
390 player_globals.parray[gg->white].opponent = -1;
391 player_globals.parray[gg->black].opponent = -1;
392 if (gg->white != command_globals.commanding_player)
393 send_prompt(gg->white);
394 if (gg->black != command_globals.commanding_player)
395 send_prompt(gg->black);
396 if ((player_globals.parray[gg->white].simul_info != NULL) &&
397 (player_globals.parray[gg->white].simul_info->numBoards))
398 player_simul_over(gg->white, g, whiteResult);
403 static int was_promoted(struct game *g, int f, int r)
405 #define BUGHOUSE_PAWN_REVERT 1
406 #ifdef BUGHOUSE_PAWN_REVERT
409 for (i = g->numHalfMoves-2; i > 0; i -= 2) {
410 if (g->moveList[i].toFile == f && g->moveList[i].toRank == r) {
411 if (g->moveList[i].piecePromotionTo)
413 if (g->moveList[i].fromFile == ALG_DROP)
415 f = g->moveList[i].fromFile;
416 r = g->moveList[i].fromRank;
423 int pIsPlaying (int p)
425 struct player *pp = &player_globals.parray[p];
427 int p1 = pp->opponent;
429 if (g < 0 || game_globals.garray[g].status != GAME_ACTIVE) {
430 pprintf (p, "You are not playing a game.\n");
434 if (game_globals.garray[g].white != p && game_globals.garray[g].black != p) {
435 /* oh oh; big bad game bug. */
436 d_printf("BUG: Player %s playing game %d according to player_globals.parray,"
437 "\n but not according to game_globals.garray.\n", pp->name, g+1);
438 pprintf (p, "Disconnecting you from game number %d.\n", g+1);
440 if (p1 >= 0 && player_globals.parray[p1].game == g
441 && game_globals.garray[g].white != p1 && game_globals.garray[g].black != p1) {
442 pprintf (p1, "Disconnecting you from game number %d.\n", g+1);
443 player_globals.parray[p1].game = -1;
450 /* add clock increments */
451 static void game_add_increment(struct player *pp, struct game *gg)
453 /* no update on first move */
454 if (gg->game_state.moveNum == 1) return;
456 if (net_globals.con[pp->socket]->timeseal) { /* does he use timeseal? */
457 if (pp->side == WHITE) {
458 gg->wRealTime += gg->wIncrement * 100;
459 gg->wTime = gg->wRealTime / 100; /* remember to conv to
461 } else if (pp->side == BLACK) {
462 gg->bRealTime += gg->bIncrement * 100; /* conv to ms */
463 gg->bTime = gg->bRealTime / 100; /* remember to conv to
467 if (gg->game_state.onMove == BLACK) {
468 gg->bTime += gg->bIncrement;
470 if (gg->game_state.onMove == WHITE) {
471 gg->wTime += gg->wIncrement;
476 /* updates clocks for a game with timeseal */
477 void timeseal_update_clocks(struct player *pp, struct game *gg)
479 /* no update on first move */
480 if (gg->game_state.moveNum == 1) return;
482 if (pp->side == WHITE) {
483 gg->wLastRealTime = gg->wRealTime;
484 gg->wTimeWhenMoved = net_globals.con[pp->socket]->time;
485 if (((gg->wTimeWhenMoved - gg->wTimeWhenReceivedMove) < 0) ||
486 (gg->wTimeWhenReceivedMove == 0)) {
487 /* might seem weird - but could be caused by a person moving BEFORE
488 he receives the board pos (this is possible due to lag) but it's
489 safe to say he moved in 0 secs :-) */
490 gg->wTimeWhenReceivedMove = gg->wTimeWhenMoved;
492 gg->wRealTime -= gg->wTimeWhenMoved - gg->wTimeWhenReceivedMove;
494 } else if (pp->side == BLACK) {
495 gg->bLastRealTime = gg->bRealTime;
496 gg->bTimeWhenMoved = net_globals.con[pp->socket]->time;
497 if (((gg->bTimeWhenMoved - gg->bTimeWhenReceivedMove) < 0) ||
498 (gg->bTimeWhenReceivedMove == 0)) {
499 /* might seem weird - but could be caused by a person moving BEFORE
500 he receives the board pos (this is possible due to lag) but it's
501 safe to say he moved in 0 secs :-) */
502 gg->bTimeWhenReceivedMove = gg->bTimeWhenMoved;
504 gg->bRealTime -= gg->bTimeWhenMoved - gg->bTimeWhenReceivedMove;
510 void process_move(int p, char *command)
512 struct player *pp = &player_globals.parray[p];
514 int g, result, len, i;
519 pprintf(p, "You are not playing or examining a game.\n");
522 decline_withdraw_offers(p, -1, -PEND_SIMUL,DO_DECLINE);
525 gg = &game_globals.garray[g];
527 if (gg->status == GAME_SETUP) {
528 if (!attempt_drop(p,g,command)) {
529 pprintf(p, "You are still setting up the position.\n");
530 pprintf(p, "Type: 'setup done' when you are finished editing.\n");
536 if (gg->status != GAME_EXAMINE) {
537 if (!pIsPlaying(p)) return;
539 if (pp->side != gg->game_state.onMove) {
540 pprintf(p, "It is not your move.\n");
543 if (gg->clockStopped) {
544 pprintf(p, "Game clock is paused, use \"unpause\" to resume.\n");
548 if ((len = strlen(command)) > 1) {
549 if (command[len - 2] == '=') {
550 switch (tolower(command[strlen(command) - 1])) {
552 pp->promote = KNIGHT;
555 pp->promote = BISHOP;
564 pprintf(p, "Don't understand that move.\n");
570 switch (parse_move(command, &gg->game_state, &move, pp->promote)) {
572 pprintf(p, "Illegal move.\n");
576 pprintf(p, "Ambiguous move.\n");
583 if (gg->status == GAME_EXAMINE) {
585 if (gg->numHalfMoves > gg->examMoveListSize) {
586 gg->examMoveListSize += 20; /* Allocate 20 moves at a time */
587 gg->examMoveList = (struct move_t *) realloc(gg->examMoveList, sizeof(struct move_t) * gg->examMoveListSize);
589 result = execute_move(&gg->game_state, &move, 1);
592 MakeFENpos(g, move.FENpos);
593 gg->examMoveList[gg->numHalfMoves - 1] = move;
595 if (gg->game_state.onMove == WHITE) {
596 gg->wTime += (gg->lastDecTime - gg->lastMoveTime);
598 gg->bTime += (gg->lastDecTime - gg->lastMoveTime);
601 if (gg->numHalfMoves == 0)
602 gg->timeOfStart = now;
603 gg->lastMoveTime = now;
604 gg->lastDecTime = now;
606 } else { /* real game */
608 if ((player_globals.parray[i].simul_info != NULL) && (player_globals.parray[i].simul_info->numBoards &&
609 (player_globals.parray[i].simul_info->boards[player_globals.parray[i].simul_info->onBoard] != g))) {
610 pprintf(p, "It isn't your turn: wait until the simul giver is at your board.\n");
613 if (net_globals.con[pp->socket]->timeseal) { /* does he use timeseal? */
614 timeseal_update_clocks(pp, &game_globals.garray[g]);
616 /* we need to reset the opp's time for receiving the board since the
617 timeseal decoder only alters the time if it's 0 Otherwise the time
618 would be changed if the player did a refresh which would screw up
620 if (pp->side == WHITE) {
621 gg->bTimeWhenReceivedMove = 0;
623 gg->wTimeWhenReceivedMove = 0;
627 game_add_increment(pp, gg);
631 if (gg->numHalfMoves > gg->moveListSize) {
632 gg->moveListSize += 20; /* Allocate 20 moves at a time */
633 gg->moveList = (struct move_t *) realloc(gg->moveList, sizeof(struct move_t) * gg->moveListSize);
635 result = execute_move(&gg->game_state, &move, 1);
636 if (result == MOVE_OK && gg->link >= 0 && move.pieceCaptured != NOPIECE) {
637 /* transfer captured piece to partner */
638 /* check if piece reverts to a pawn */
639 if (was_promoted(&game_globals.garray[g], move.toFile, move.toRank))
640 update_holding(gg->link, colorval(move.pieceCaptured) | PAWN);
642 update_holding(gg->link, move.pieceCaptured);
646 if (gg->numHalfMoves > 1) {
647 move.tookTime = move.atTime - gg->lastMoveTime;
649 move.tookTime = move.atTime - gg->startTime;
651 gg->lastMoveTime = now;
652 gg->lastDecTime = now;
653 move.wTime = gg->wTime;
654 move.bTime = gg->bTime;
656 if (net_globals.con[pp->socket]->timeseal) { /* does he use timeseal? */
657 if (pp->side == WHITE) {
658 move.tookTime = (game_globals.garray[pp->game].wTimeWhenMoved -
659 game_globals.garray[pp->game].wTimeWhenReceivedMove) / 100;
661 move.tookTime = (game_globals.garray[pp->game].bTimeWhenMoved -
662 game_globals.garray[pp->game].bTimeWhenReceivedMove) / 100;
666 if (gg->numHalfMoves <= 2) {
670 MakeFENpos(g, move.FENpos);
671 gg->moveList[gg->numHalfMoves - 1] = move;
676 if (result == MOVE_ILLEGAL) {
677 pprintf(p, "Internal error, illegal move accepted!\n");
679 if ((result == MOVE_OK) && (gg->status == GAME_EXAMINE)) {
682 for (p1 = 0; p1 < player_globals.p_num; p1++) {
683 if (player_globals.parray[p1].status != PLAYER_PROMPT)
685 if (player_is_observe(p1, g) || player_globals.parray[p1].game == g) {
686 pprintf(p1, "%s moves: %s\n", pp->name, move.algString);
690 if (result == MOVE_CHECKMATE) {
691 if (gg->status == GAME_EXAMINE) {
694 for (p1 = 0; p1 < player_globals.p_num; p1++) {
695 if (player_globals.parray[p1].status != PLAYER_PROMPT)
697 if (player_is_observe(p1, g) || player_globals.parray[p1].game == g) {
698 pprintf(p1, "%s has been checkmated.\n",
699 (CToggle(gg->game_state.onMove) == BLACK) ? "White" : "Black");
703 game_ended(g, CToggle(gg->game_state.onMove), END_CHECKMATE);
706 if (result == MOVE_STALEMATE) {
707 if (gg->status == GAME_EXAMINE) {
710 for (p1 = 0; p1 < player_globals.p_num; p1++) {
711 if (player_globals.parray[p1].status != PLAYER_PROMPT)
713 if (player_is_observe(p1, g) || player_globals.parray[p1].game == g) {
714 pprintf(p1, "Stalemate.\n");
718 game_ended(g, CToggle(gg->game_state.onMove), END_STALEMATE);
721 if (result == MOVE_NOMATERIAL) {
722 if (gg->status == GAME_EXAMINE) {
725 for (p1 = 0; p1 < player_globals.p_num; p1++) {
726 if (player_globals.parray[p1].status != PLAYER_PROMPT)
728 if (player_is_observe(p1, g) || player_globals.parray[p1].game == g) {
729 pprintf(p1, "No mating material.\n");
733 game_ended(g, CToggle(gg->game_state.onMove), END_NOMATERIAL);
738 int com_resign(int p, param_list param)
740 struct player *pp = &player_globals.parray[p];
741 int g, o, oconnected;
743 if (param[0].type == TYPE_NULL) {
748 decline_withdraw_offers(p, -1, -1, DO_DECLINE);
749 game_ended(g, (game_globals.garray[g].white == p) ? BLACK : WHITE, END_RESIGN);
751 } else if (FindPlayer(p, param[0].val.word, &o, &oconnected)) {
753 if (game_read(g, p, o) < 0) {
754 if (game_read(g, o, p) < 0) {
755 pprintf(p, "You have no stored game with %s\n", player_globals.parray[o].name);
760 game_globals.garray[g].white = o;
761 game_globals.garray[g].black = p;
764 game_globals.garray[g].white = p;
765 game_globals.garray[g].black = o;
767 pprintf(p, "You resign your stored game with %s\n", player_globals.parray[o].name);
768 pcommand(p, "message %s I have resigned our stored game \"%s vs. %s.\"",
769 player_globals.parray[o].name,
770 player_globals.parray[game_globals.garray[g].white].name,
771 player_globals.parray[game_globals.garray[g].black].name);
772 game_delete(game_globals.garray[g].white, game_globals.garray[g].black);
773 game_ended(g, (game_globals.garray[g].white == p) ? BLACK : WHITE, END_RESIGN);
780 static int Check50MoveRule (int p, int g)
782 int num_reversible = game_globals.garray[g].numHalfMoves;
784 if (game_globals.garray[g].game_state.lastIrreversable >= 0) {
785 num_reversible -= game_globals.garray[g].game_state.lastIrreversable;
787 if (num_reversible > 99) {
788 game_ended(g, (game_globals.garray[g].white == p) ? BLACK : WHITE, END_50MOVERULE);
794 static char *GetFENpos (int g, int half_move)
797 return game_globals.garray[g].FENstartPos;
798 else return game_globals.garray[g].moveList[half_move].FENpos;
801 static int CheckRepetition (int p, int g)
803 struct player *pp = &player_globals.parray[p];
804 struct pending* pend;
806 int flag1 = 1, flag2 = 1;
807 char *pos1 = GetFENpos (g, game_globals.garray[g].numHalfMoves - 1);
808 char *pos2 = GetFENpos (g, game_globals.garray[g].numHalfMoves);
811 if (game_globals.garray[g].numHalfMoves < 8) /* can't have three repeats any quicker. */
814 for (move_num = game_globals.garray[g].game_state.lastIrreversable;
815 move_num < game_globals.garray[g].numHalfMoves - 1; move_num++) {
816 pos = GetFENpos (g, move_num);
817 if (strlen(pos1) == strlen(pos) && !strcmp(pos1, pos))
819 if (strlen(pos2) == strlen(pos) && !strcmp(pos2, pos))
822 if (flag1 >= 3 || flag2 >= 3) {
823 if ((pend = find_pend(pp->opponent, p, PEND_DRAW)) != NULL) {
824 delete_pending(pend);
825 decline_withdraw_offers(p, -1, -1,DO_DECLINE);
827 game_ended(g, (game_globals.garray[g].white == p) ? BLACK : WHITE, END_REPETITION);
833 int com_draw(int p, param_list param)
835 struct player *pp = &player_globals.parray[p];
836 struct pending* pend;
837 int p1, g = pp->game;
839 if (!pIsPlaying(p)) {
842 if (Check50MoveRule (p, g) || CheckRepetition(p, g)) {
847 if ((player_globals.parray[p1].simul_info != NULL) && (player_globals.parray[p1].simul_info->numBoards &&
848 player_globals.parray[p1].simul_info->boards[player_globals.parray[p1].simul_info->onBoard] != g)) {
849 pprintf(p, "You can only make requests when the simul player is at your board.\n");
853 if ((pend = (find_pend(pp->opponent, p, PEND_DRAW))) != NULL) {
854 delete_pending(pend);
855 decline_withdraw_offers(p, -1, -1,DO_DECLINE);
856 game_ended(g, (game_globals.garray[g].white == p) ? BLACK : WHITE, END_AGREEDDRAW);
858 pprintf(pp->opponent, "\n");
859 pprintf_highlight(pp->opponent, "%s", pp->name);
860 pprintf_prompt(pp->opponent, " offers you a draw.\n");
861 pprintf(p, "Draw request sent.\n");
862 add_request(p, pp->opponent, PEND_DRAW);
867 int com_pause(int p, param_list param)
869 struct player *pp = &player_globals.parray[p];
871 struct pending* pend;
873 if (!pIsPlaying(p)) {
877 if (game_globals.garray[g].wTime == 0) {
878 pprintf(p, "You can't pause untimed games.\n");
881 if (game_globals.garray[g].clockStopped) {
882 pprintf(p, "Game is already paused, use \"unpause\" to resume.\n");
885 if ((pend = find_pend(pp->opponent, p, PEND_PAUSE)) != NULL) {
886 delete_pending(pend);
887 game_globals.garray[g].clockStopped = 1;
888 /* Roll back the time */
889 if (game_globals.garray[g].game_state.onMove == WHITE) {
890 game_globals.garray[g].wTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
892 game_globals.garray[g].bTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
895 if (game_globals.garray[g].numHalfMoves == 0)
896 game_globals.garray[g].timeOfStart = now;
897 game_globals.garray[g].lastMoveTime = now;
898 game_globals.garray[g].lastDecTime = now;
900 pprintf_prompt(pp->opponent, "\n%s accepted pause. Game clock paused.\n",
902 pprintf(p, "Game clock paused.\n");
904 pprintf(pp->opponent, "\n");
905 pprintf_highlight(pp->opponent, "%s", pp->name);
906 pprintf_prompt(pp->opponent, " requests to pause the game.\n");
907 pprintf(p, "Pause request sent.\n");
908 add_request(p, pp->opponent, PEND_PAUSE);
913 int com_unpause(int p, param_list param)
915 struct player *pp = &player_globals.parray[p];
918 struct pending* pend;
920 if (!pIsPlaying(p)) {
926 if (!game_globals.garray[g].clockStopped) {
927 pprintf(p, "Game is not paused.\n");
930 if ((pend = find_pend(pp->opponent, p, PEND_UNPAUSE)) != NULL) {
931 delete_pending(pend);
932 game_globals.garray[g].clockStopped = 0;
934 if (game_globals.garray[g].numHalfMoves == 0)
935 game_globals.garray[g].timeOfStart = now;
936 game_globals.garray[g].lastMoveTime = now;
937 game_globals.garray[g].lastDecTime = now;
939 pprintf(p, "Game clock resumed.\n");
940 pprintf_prompt(pp->opponent, "\nGame clock resumed.\n");
942 pprintf(pp->opponent, "\n");
943 pprintf_highlight(pp->opponent, "%s", pp->name);
944 pprintf_prompt(pp->opponent, " requests to unpause the game.\n");
945 pprintf(p, "Unpause request sent.\n");
946 add_request(p, pp->opponent, PEND_UNPAUSE);
951 int com_abort(int p, param_list param)
953 struct player *pp = &player_globals.parray[p];
954 struct pending* pend;
955 int p1, g, myColor, yourColor, myGTime, yourGTime;
963 if (p == game_globals.garray[g].white) {
966 myGTime = game_globals.garray[g].wTime;
967 yourGTime = game_globals.garray[g].bTime;
971 myGTime = game_globals.garray[g].bTime;
972 yourGTime = game_globals.garray[g].wTime;
974 if ((player_globals.parray[p1].simul_info != NULL) &&
975 (player_globals.parray[p1].simul_info->numBoards &&
976 player_globals.parray[p1].simul_info->boards[player_globals.parray[p1].simul_info->onBoard] != g)) {
977 pprintf(p, "You can only make requests when the simul player is at your board.\n");
980 if ((pend = find_pend(p1, p, PEND_ABORT)) != NULL) {
981 delete_pending(pend);
982 decline_withdraw_offers(p, -1, -1,DO_DECLINE);
983 game_ended(g, yourColor, END_ABORT);
987 if (net_globals.con[pp->socket]->timeseal
988 && game_globals.garray[g].game_state.onMove == myColor
989 && game_globals.garray[g].flag_pending == FLAG_ABORT) {
990 /* It's my move, opponent has asked for abort; I lagged out,
991 my timeseal prevented courtesyabort, and I am sending an abort
992 request before acknowledging (and processing) my opponent's
993 courtesyabort. OK, let's abort already :-). */
994 decline_withdraw_offers(p, -1, -1,DO_DECLINE);
995 game_ended(g, yourColor, END_ABORT);
998 if (net_globals.con[player_globals.parray[p1].socket]->timeseal) { /* opp uses timeseal? */
1000 int yourRealTime = (myColor == WHITE ? game_globals.garray[g].bRealTime
1001 : game_globals.garray[g].wRealTime);
1002 if (myGTime > 0 && yourGTime <= 0 && yourRealTime > 0) {
1003 /* Override courtesyabort; opponent still has time. Check for lag. */
1006 if (game_globals.garray[g].game_state.onMove != myColor
1007 && game_globals.garray[g].flag_pending != FLAG_CHECKING) {
1008 /* Opponent may be lagging; let's ask. */
1009 game_globals.garray[g].flag_pending = FLAG_ABORT;
1010 game_globals.garray[g].flag_check_time = time(0);
1011 pprintf(p, "Opponent has timeseal; trying to courtesyabort.\n");
1012 pprintf(p1, "\n[G]\n");
1018 if (myGTime > 0 && yourGTime <= 0 && courtesyOK) {
1019 /* player wants to abort + opponent is out of time = courtesyabort */
1020 pprintf(p, "Since you have time, and your opponent has none, the game has been aborted.");
1021 pprintf(p1, "Your opponent has aborted the game rather than calling your flag.");
1022 decline_withdraw_offers(p, -1, -1, DO_DECLINE);
1023 game_ended(g, myColor, END_COURTESY);
1026 pprintf_highlight(p1, "%s", pp->name);
1027 pprintf(p1, " would like to abort the game; ");
1028 pprintf_prompt(p1, "type \"abort\" to accept.\n");
1029 pprintf(p, "Abort request sent.\n");
1030 add_request(p, p1, PEND_ABORT);
1036 static int player_has_mating_material(struct game_state_t *gs, int color)
1040 int minor_pieces = 0;
1042 for (i = 0; i < 8; i++)
1043 for (j = 0; j < 8; j++) {
1044 piece = gs->board[i][j];
1045 switch (piecetype(piece)) {
1048 if (iscolor(piece, color))
1055 if (iscolor(piece, color))
1059 return ((minor_pieces > 1) ? 1 : 0);
1062 int com_flag(int p, param_list param)
1064 struct player *pp = &player_globals.parray[p];
1069 if (!pIsPlaying(p)) {
1074 gg = &game_globals.garray[g];
1076 myColor = (p == gg->white ? WHITE : BLACK);
1077 if (gg->type == TYPE_UNTIMED) {
1078 pprintf(p, "You can't flag an untimed game.\n");
1081 if (gg->numHalfMoves < 2) {
1082 pprintf(p, "You cannot flag before both players have moved.\nUse abort instead.\n");
1085 game_update_time(g);
1088 int myTime, yourTime, opp = pp->opponent, serverTime;
1090 if (net_globals.con[pp->socket]->timeseal) { /* does caller use timeseal? */
1091 myTime = (myColor==WHITE?gg->wRealTime:gg->bRealTime);
1093 myTime = (myColor == WHITE?gg->wTime:gg->bTime);
1095 serverTime = (myColor == WHITE?gg->bTime:gg->wTime);
1097 if (net_globals.con[player_globals.parray[opp].socket]->timeseal) { /* opp uses timeseal? */
1098 yourTime = (myColor == WHITE?gg->bRealTime:gg->wRealTime);
1100 yourTime = serverTime;
1103 /* the clocks to compare are now in myTime and yourTime */
1104 if ((myTime <= 0) && (yourTime <= 0)) {
1105 decline_withdraw_offers(p, -1, -1,DO_DECLINE);
1106 game_ended(g, myColor, END_BOTHFLAG);
1111 /* Opponent still has time, but if that's only because s/he
1112 * may be lagging, we should ask for an acknowledgement and then
1113 * try to call the flag. */
1115 if (serverTime <= 0 && gg->game_state.onMove != myColor
1116 && gg->flag_pending != FLAG_CHECKING) {
1117 /* server time thinks opponent is down, but RealTIme disagrees.
1118 * ask client to acknowledge it's alive. */
1119 gg->flag_pending = FLAG_CALLED;
1120 gg->flag_check_time = time(0);
1121 pprintf(p, "Opponent has timeseal; checking if (s)he's lagging.\n");
1122 pprintf (opp, "\n[G]\n");
1126 /* if we're here, it means one of:
1127 * 1. the server agrees opponent has time, whether lagging or not.
1128 * 2. opp. has timeseal (if yourTime != serverTime), had time left
1129 * after the last move (yourTime > 0), and it's still your move.
1130 * 3. we're currently checking a flag call after having receiving
1131 * acknowledgement from the other timeseal (and would have reset
1132 * yourTime if the flag were down). */
1134 pprintf(p, "Your opponent is not out of time!\n");
1139 decline_withdraw_offers(p, -1, -1,DO_DECLINE);
1140 if (player_has_mating_material(&gg->game_state, myColor))
1141 game_ended(g, myColor, END_FLAG);
1143 game_ended(g, myColor, END_FLAGNOMATERIAL);
1147 int com_adjourn(int p, param_list param)
1149 struct player *pp = &player_globals.parray[p];
1150 struct pending* pend;
1151 int p1, g, myColor, yourColor;
1158 if (!CheckPFlag(p, PFLAG_REG) || !CheckPFlag(p, PFLAG_REG)) {
1159 pprintf(p, "Both players must be registered to adjourn a game. Use \"abort\".\n");
1162 if (game_globals.garray[g].link >= 0) {
1163 pprintf(p, "Bughouse games cannot be adjourned.\n");
1166 myColor = (p == game_globals.garray[g].white ? WHITE : BLACK);
1167 yourColor = (myColor == WHITE ? BLACK : WHITE);
1169 if ((pend = find_pend(p1, p, PEND_ADJOURN)) != NULL) {
1170 delete_pending(pend);
1171 decline_withdraw_offers(p, -1, -1,DO_DECLINE);
1172 game_ended(pp->game, yourColor, END_ADJOURN);
1174 game_update_time(g);
1175 if (((myColor == WHITE) && (game_globals.garray[g].wTime > 0) && (game_globals.garray[g].bTime <= 0))
1176 || ((myColor == BLACK) && (game_globals.garray[g].bTime > 0) && (game_globals.garray[g].wTime <= 0))) {
1177 /* player wants to adjourn + opponent is out of time = courtesyadjourn */
1178 pprintf(p, "Since you have time, and your opponent has none, the game has been adjourned.");
1179 pprintf(p1, "Your opponent has adjourned the game rather than calling your flag.");
1180 decline_withdraw_offers(p, -1, -1,DO_DECLINE);
1181 game_ended(g, myColor, END_COURTESYADJOURN);
1184 pprintf_highlight(p1, "%s", pp->name);
1185 pprintf(p1, " would like to adjourn the game; ");
1186 pprintf_prompt(p1, "type \"adjourn\" to accept.\n");
1187 pprintf(p, "Adjourn request sent.\n");
1188 add_request(p, p1, PEND_ADJOURN);
1194 int com_takeback(int p, param_list param)
1196 struct player *pp = &player_globals.parray[p];
1197 int nHalfMoves = 1, g, i, p1, pend_half_moves;
1198 struct pending* from;
1204 if ((player_globals.parray[p1].simul_info != NULL) &&
1205 (player_globals.parray[p1].simul_info->numBoards &&
1206 player_globals.parray[p1].simul_info->boards[player_globals.parray[p1].simul_info->onBoard] !=
1208 pprintf(p, "You can only make requests when the simul player is at your board.\n");
1213 if (game_globals.garray[g].link >= 0) {
1214 pprintf(p, "Takeback not implemented for bughouse games yet.\n");
1217 if (param[0].type == TYPE_INT) {
1218 nHalfMoves = param[0].val.integer;
1219 if (nHalfMoves <= 0) {
1220 pprintf (p,"You can't takeback less than 1 move.\n");
1224 if ((from = find_pend(pp->opponent, p, PEND_TAKEBACK)) != NULL) {
1225 pend_half_moves = from->wtime;
1226 delete_pending(from);
1227 if (pend_half_moves == nHalfMoves) {
1228 /* Doing the takeback */
1229 decline_withdraw_offers(p, -1, -PEND_SIMUL,DO_DECLINE);
1230 for (i = 0; i < nHalfMoves; i++) {
1231 if (backup_move(g, REL_GAME) != MOVE_OK) {
1232 pprintf(game_globals.garray[g].white, "Can only backup %d moves\n", i);
1233 pprintf(game_globals.garray[g].black, "Can only backup %d moves\n", i);
1238 game_globals.garray[g].wTimeWhenReceivedMove = 0;
1239 game_globals.garray[g].bTimeWhenReceivedMove = 0;
1244 if (!game_globals.garray[g].numHalfMoves) {
1245 pprintf(p, "There are no moves in your game.\n");
1246 pprintf_prompt(pp->opponent, "\n%s has declined the takeback request.\n",
1251 if (game_globals.garray[g].numHalfMoves < nHalfMoves) {
1252 pprintf(p, "There are only %d half moves in your game.\n", game_globals.garray[g].numHalfMoves);
1253 pprintf_prompt(pp->opponent, "\n%s has declined the takeback request.\n",
1257 pprintf(p, "You disagree on the number of half-moves to takeback.\n");
1258 pprintf(p, "Alternate takeback request sent.\n");
1259 pprintf_prompt(pp->opponent, "\n%s proposes a different number (%d) of half-move(s).\n", pp->name, nHalfMoves);
1260 from = add_request(p, pp->opponent, PEND_TAKEBACK);
1261 from->wtime = nHalfMoves;
1265 if (!game_globals.garray[g].numHalfMoves) {
1266 pprintf(p, "There are no moves in your game.\n");
1269 if (game_globals.garray[g].numHalfMoves < nHalfMoves) {
1270 pprintf(p, "There are only %d half moves in your game.\n", game_globals.garray[g].numHalfMoves);
1273 pprintf(pp->opponent, "\n");
1274 pprintf_highlight(pp->opponent, "%s", pp->name);
1275 pprintf_prompt(pp->opponent, " would like to take back %d half move(s).\n",
1277 pprintf(p, "Takeback request sent.\n");
1278 from = add_request(p, pp->opponent, PEND_TAKEBACK);
1279 from->wtime = nHalfMoves;
1285 int com_switch(int p, param_list param)
1287 struct player *pp = &player_globals.parray[p];
1288 int g = pp->game, tmp, now, p1;
1290 struct pending* pend;
1296 if ((player_globals.parray[p1].simul_info != NULL) && (player_globals.parray[p1].simul_info->numBoards &&
1297 player_globals.parray[p1].simul_info->boards[player_globals.parray[p1].simul_info->onBoard] != g)) {
1298 pprintf(p, "You can only make requests when the simul player is at your board.\n");
1302 if (game_globals.garray[g].link >= 0) {
1303 pprintf(p, "Switch not implemented for bughouse games.\n");
1306 if ((pend = find_pend(pp->opponent, p, PEND_SWITCH)) != NULL) {
1307 delete_pending(pend);
1308 /* Doing the switch */
1309 decline_withdraw_offers(p, -1, -PEND_SIMUL,DO_DECLINE);
1311 tmp = game_globals.garray[g].white;
1312 game_globals.garray[g].white = game_globals.garray[g].black;
1313 game_globals.garray[g].black = tmp;
1314 pp->side = (pp->side == WHITE) ? BLACK : WHITE;
1315 strTmp = strdup(game_globals.garray[g].white_name);
1316 strcpy(game_globals.garray[g].white_name, game_globals.garray[g].black_name);
1317 strcpy(game_globals.garray[g].black_name, strTmp);
1320 player_globals.parray[pp->opponent].side =
1321 (player_globals.parray[pp->opponent].side == WHITE) ? BLACK : WHITE;
1322 /* Roll back the time */
1323 if (game_globals.garray[g].game_state.onMove == WHITE) {
1324 game_globals.garray[g].wTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
1326 game_globals.garray[g].bTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
1329 if (game_globals.garray[g].numHalfMoves == 0)
1330 game_globals.garray[g].timeOfStart = now;
1331 game_globals.garray[g].lastMoveTime = now;
1332 game_globals.garray[g].lastDecTime = now;
1336 if (game_globals.garray[g].rated && game_globals.garray[g].numHalfMoves > 0) {
1337 pprintf(p, "You cannot switch sides once a rated game is underway.\n");
1340 pprintf(pp->opponent, "\n");
1341 pprintf_highlight(pp->opponent, "%s", pp->name);
1342 pprintf_prompt(pp->opponent, " would like to switch sides.\nType \"accept\" to switch sides, or \"decline\" to refuse.\n");
1343 pprintf(p, "Switch request sent.\n");
1344 add_request(p, pp->opponent, PEND_SWITCH);
1348 int com_time(int p, param_list param)
1350 struct player *pp = &player_globals.parray[p];
1353 if (param[0].type == TYPE_NULL) {
1358 g = GameNumFromParam(p, &p1, ¶m[0]);
1362 if ((g < 0) || (g >= game_globals.g_num) || (game_globals.garray[g].status != GAME_ACTIVE)) {
1363 pprintf(p, "There is no such game.\n");
1366 game_update_time(g);
1367 pprintf(p, "White (%s) : %d mins, %d secs\n",
1368 player_globals.parray[game_globals.garray[g].white].name,
1369 game_globals.garray[g].wTime / 600,
1370 (game_globals.garray[g].wTime - ((game_globals.garray[g].wTime / 600) * 600)) / 10);
1371 pprintf(p, "Black (%s) : %d mins, %d secs\n",
1372 player_globals.parray[game_globals.garray[g].black].name,
1373 game_globals.garray[g].bTime / 600,
1374 (game_globals.garray[g].bTime - ((game_globals.garray[g].bTime / 600) * 600)) / 10);
1378 int com_ptime(int p, param_list param)
1380 struct player *pp = &player_globals.parray[p];
1381 int retval, part = pp->partner;
1384 pprintf(p, "You do not have a partner.\n");
1387 retval = pcommand (p, "time %s", player_globals.parray[part].name);
1388 if (retval == COM_OK)
1389 return COM_OK_NOPROMPT;
1394 int com_boards(int p, param_list param)
1396 char *category = NULL;
1397 char dname[MAX_FILENAME_SIZE];
1401 if (param[0].type == TYPE_WORD)
1402 category = param[0].val.word;
1404 pprintf(p, "Boards Available For Category %s:\n", category);
1405 sprintf(dname, "%s/%s", BOARD_DIR, category);
1407 pprintf(p, "Categories Available:\n");
1408 sprintf(dname, "%s", BOARD_DIR);
1410 dirp = opendir(dname);
1412 pprintf(p, "No such category %s, try \"boards\".\n", category);
1416 /* YUK! what a mess, how about printing an ordered directory? - DAV*/
1418 for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
1419 if (!strcmp(dp->d_name, "."))
1421 if (!strcmp(dp->d_name, ".."))
1423 pprintf(p, "%s\n", dp->d_name);
1429 int com_simmatch(int p, param_list param)
1431 struct player *pp = &player_globals.parray[p];
1432 int p1, g, adjourned;
1435 struct pending* pend;
1437 char* category = NULL;
1438 char fname[MAX_FILENAME_SIZE];
1441 if (game_globals.garray[pp->game].status == GAME_EXAMINE) {
1442 pprintf(p, "You are still examining a game.\n");
1445 if (game_globals.garray[pp->game].status == GAME_SETUP) {
1446 pprintf(p, "You are still setting up a position.\n");
1450 p1 = player_find_part_login(param[0].val.word);
1452 pprintf(p, "No user named \"%s\" is logged in.\n", param[0].val.word);
1456 pprintf(p, "You can't simmatch yourself!\n");
1459 if ((pend = find_pend(p1, p, PEND_SIMUL)) != NULL) {
1461 /* Accepting Simul ! */
1463 if ((pp->simul_info != NULL) &&
1464 (pp->simul_info->numBoards >= MAX_SIMUL)) {
1465 pprintf(p, "You are already playing the maximum of %d boards.\n", MAX_SIMUL);
1466 pprintf(p1, "Simul request removed, boards filled.\n");
1467 delete_pending(pend);
1470 unobserveAll(p); /* stop observing when match starts */
1475 if (game_read(g, p, p1) >= 0) {
1477 delete_pending(pend);
1480 if (!adjourned) { /* no adjourned game, so begin a new game */
1482 if ((pend->category != NULL) && (pend->board_type != NULL)) {
1483 board = strdup(pend->category);
1484 category = strdup(pend->board_type);
1487 delete_pending(pend);
1489 if (create_new_match(g,p, p1, 0, 0, 0, 0, 0, ((board == NULL) ? "\0" : board), ((category == NULL) ? "\0" : category), 1,1) == COM_FAILED) {
1490 pprintf(p, "There was a problem creating the new match.\n");
1491 pprintf_prompt(p1, "There was a problem creating the new match.\n");
1494 if (board != NULL) {
1501 if (board != NULL) {
1506 } else { /* resume adjourned game */
1509 sprintf(tmp, "{Game %d (%s vs. %s) Continuing %s %s simul.}\n", g + 1, pp->name, player_globals.parray[p1].name, rstr[game_globals.garray[g].rated], bstr[game_globals.garray[g].type]);
1513 game_globals.garray[g].white = p;
1514 game_globals.garray[g].black = p1;
1515 game_globals.garray[g].status = GAME_ACTIVE;
1516 game_globals.garray[g].startTime = tenth_secs();
1517 game_globals.garray[g].lastMoveTime = game_globals.garray[g].startTime;
1518 game_globals.garray[g].lastDecTime = game_globals.garray[g].startTime;
1522 player_globals.parray[p1].game = g;
1523 player_globals.parray[p1].opponent = p;
1524 player_globals.parray[p1].side = BLACK;
1528 if (pp->simul_info == NULL) {
1529 pp->simul_info = (struct simul_info_t *) malloc(sizeof(struct simul_info_t));
1530 pp->simul_info->numBoards = 0;
1531 pp->simul_info->onBoard = 0;
1532 pp->simul_info->num_wins = pp->simul_info->num_draws
1533 = pp->simul_info->num_losses = 0;
1535 num = pp->simul_info->numBoards;
1536 /* pp->simul_info->results[num] = -1; */
1537 pp->simul_info->boards[num] = pp->game;
1538 pp->simul_info->numBoards++;
1539 if (pp->simul_info->numBoards > 1 &&
1540 pp->simul_info->onBoard >= 0)
1541 player_goto_board(p, pp->simul_info->onBoard);
1543 pp->simul_info->onBoard = 0;
1546 if (find_pend(-1, p, PEND_SIMUL) != NULL) {
1547 pprintf(p, "You cannot be the simul giver and request to join another simul.\nThat would just be too confusing for me and you.\n");
1550 if (pp->simul_info != NULL) {
1551 if (pp->simul_info->numBoards) {
1552 pprintf(p, "You cannot be the simul giver and request to join another simul.\nThat would just be too confusing for me and you.\n");
1557 pprintf(p, "You are already playing a game.\n");
1560 if (!CheckPFlag(p1, PFLAG_SIMOPEN)) {
1561 pprintf_highlight(p, "%s", player_globals.parray[p1].name);
1562 pprintf(p, " is not open to receiving simul requests.\n");
1565 if ((player_globals.parray[p1].simul_info != NULL) && (player_globals.parray[p1].simul_info->numBoards >= MAX_SIMUL)) {
1566 pprintf_highlight(p, "%s", player_globals.parray[p1].name);
1567 pprintf(p, " is already playing the maximum of %d boards.\n", MAX_SIMUL);
1571 /* loon: checking for some crazy situations we can't allow :) */
1573 if ((player_globals.parray[p1].simul_info != NULL) && (player_globals.parray[p1].game >=0) && (player_globals.parray[p1].simul_info->numBoards == 0)) {
1574 pprintf_highlight(p, "%s", player_globals.parray[p1].name);
1575 if (player_globals.parray[game_globals.garray[player_globals.parray[p1].game].white].simul_info->numBoards) {
1576 pprintf(p, " is playing in ");
1577 pprintf_highlight(p, "%s", player_globals.parray[player_globals.parray[p1].opponent].name);
1578 pprintf(p, "'s simul, and can't accept.\n");
1580 pprintf(p, " can't begin a simul while playing a non-simul game.\n");
1585 g = game_new(); /* Check if an adjourned untimed game */
1586 adjourned = ((game_read(g, p, p1) < 0) && (game_read(g, p1, p) < 0)) ? 0 : 1;
1588 if (!(game_globals.garray[g].type == TYPE_UNTIMED))
1593 pend = add_request(p, p1, PEND_SIMUL);
1595 if ((param[1].type == TYPE_WORD) && (param[2].type == TYPE_WORD)) {
1597 sprintf(fname, "%s/%s/%s", BOARD_DIR, param[1].val.word , param[2].val.word);
1598 if (!file_exists(fname)) {
1599 pprintf(p, "No such category/board: %s/%s\n", param[1].val.word , param[2].val.word);
1602 pend->category = strdup(param[1].val.word);
1603 pend->board_type = strdup(param[2].val.word);
1605 pend->category = NULL;
1606 pend->board_type = NULL;
1610 pprintf_highlight(p1, "%s", pp->name);
1612 pprintf_prompt(p1, " requests to continue an adjourned simul game.\n");
1613 pprintf(p, "Request to resume simul sent. Adjourned game found.\n");
1615 if (pend->category == NULL)
1616 pprintf_prompt(p1, " requests to join a simul match with you.\n");
1618 pprintf_prompt(p1, " requests to join a %s %s simul match with you.\n",
1619 pend->category,pend->board_type);
1620 pprintf(p, "Simul match request sent.\n");
1625 int com_goboard(int p, param_list param)
1627 struct player *pp = &player_globals.parray[p];
1628 int on, g, p1, gamenum;
1630 if (pp->simul_info == NULL) {
1631 pprintf(p, "You are not giving a simul.\n");
1635 if (!pp->simul_info->numBoards) {
1636 pprintf(p, "You are not giving a simul.\n");
1640 if (param[0].type == TYPE_WORD) {
1642 p1 = player_find_part_login(param[0].val.word);
1644 pprintf(p, "No user named \"%s\" is logged in.\n", param[0].val.word);
1648 pprintf(p, "You can't goboard yourself!\n");
1652 gamenum = player_globals.parray[p1].game;
1654 pprintf (p,"%s is not playing a game.\n", player_globals.parray[p1].login);
1659 gamenum = param[0].val.integer - 1;
1664 on = pp->simul_info->onBoard;
1665 g = pp->simul_info->boards[on];
1667 pprintf(p, "You are already at that board!\n");
1670 if (pp->simul_info->numBoards > 1) {
1671 decline_withdraw_offers(p, -1, -PEND_SIMUL,DO_DECLINE);
1672 if (player_goto_simulgame_bynum(p, gamenum) !=-1) {
1674 pprintf(game_globals.garray[g].black, "\n");
1675 pprintf_highlight(game_globals.garray[g].black, "%s", pp->name);
1676 pprintf_prompt(game_globals.garray[g].black, " has moved away from your board.\n");
1679 pprintf(p, "You are not playing that game/person.\n");
1681 pprintf(p, "You are only playing one board!\n");
1685 int com_simnext(int p, param_list param)
1687 struct player *pp = &player_globals.parray[p];
1690 if (pp->simul_info == NULL) {
1691 pprintf(p, "You are not giving a simul.\n");
1695 if (!pp->simul_info->numBoards) {
1696 pprintf(p, "You are not giving a simul.\n");
1700 if (pp->simul_info->numBoards > 1) {
1701 decline_withdraw_offers(p, -1, -PEND_SIMUL,DO_DECLINE);
1702 on = pp->simul_info->onBoard;
1703 g = pp->simul_info->boards[on];
1705 pprintf(game_globals.garray[g].black, "\n");
1706 pprintf_highlight(game_globals.garray[g].black, "%s", pp->name);
1707 pprintf_prompt(game_globals.garray[g].black, " is moving away from your board.\n");
1708 player_goto_next_board(p);
1711 pprintf(p, "You are only playing one board!\n");
1715 int com_simprev(int p, param_list param)
1717 struct player *pp = &player_globals.parray[p];
1720 if (pp->simul_info == NULL) {
1721 pprintf(p, "You are not giving a simul.\n");
1725 if (!pp->simul_info->numBoards) {
1726 pprintf(p, "You are not giving a simul.\n");
1729 if (pp->simul_info->numBoards > 1) {
1730 decline_withdraw_offers(p, -1, -PEND_SIMUL,DO_DECLINE);
1731 on = pp->simul_info->onBoard;
1732 g = pp->simul_info->boards[on];
1734 pprintf(game_globals.garray[g].black, "\n");
1735 pprintf_highlight(game_globals.garray[g].black, "%s", pp->name);
1736 pprintf_prompt(game_globals.garray[g].black, " is moving back to the previous board.\n");
1738 player_goto_prev_board(p);
1740 pprintf(p, "You are only playing one board!\n");
1744 int com_simgames(int p, param_list param)
1748 if (param[0].type == TYPE_WORD) {
1749 if ((p1 = player_find_part_login(param[0].val.word)) < 0) {
1750 pprintf(p, "No player named %s is logged in.\n", param[0].val.word);
1755 pprintf(p, "You are playing %d simultaneous games.\n",
1756 player_num_active_boards(p1));
1758 pprintf(p, "%s is playing %d simultaneous games.\n", player_globals.parray[p1].name,
1759 player_num_active_boards(p1));
1763 int com_simpass(int p, param_list param)
1765 struct player *pp = &player_globals.parray[p];
1772 p1 = game_globals.garray[g].white;
1774 if (player_globals.parray[p1].simul_info == NULL) {
1775 pprintf(p, "You are not participating in a simul.\n");
1779 if (!player_globals.parray[p1].simul_info->numBoards) {
1780 pprintf(p, "You are not participating in a simul.\n");
1784 pprintf(p, "You are the simul holder and cannot pass!\n");
1787 if (player_num_active_boards(p1) == 1) {
1788 pprintf(p, "This is the only game, so passing is futile.\n");
1791 on = player_globals.parray[p1].simul_info->onBoard;
1792 if (player_globals.parray[p1].simul_info->boards[on] != g) {
1793 pprintf(p, "You cannot pass until the simul holder arrives!\n");
1796 if (game_globals.garray[g].passes >= MAX_SIMPASS) {
1798 pprintf(p, "You have reached your maximum of %d pass(es).\n", MAX_SIMPASS);
1799 pprintf(p, "Please move IMMEDIATELY!\n");
1800 pprintf_highlight(p1, "%s", pp->name);
1801 pprintf_prompt(p1, " tried to pass, but is out of passes.\n");
1804 decline_withdraw_offers(p, -1, -PEND_SIMUL,DO_DECLINE);
1806 game_globals.garray[g].passes++;
1807 pprintf(p, "You have passed and have %d pass(es) left.\n",
1808 (MAX_SIMPASS - game_globals.garray[g].passes));
1809 pprintf_highlight(p1, "%s", pp->name);
1810 pprintf_prompt(p1, " has decided to pass and has %d pass(es) left.\n",
1811 (MAX_SIMPASS - game_globals.garray[g].passes));
1812 player_goto_next_board(p1);
1816 int com_simabort(int p, param_list param)
1818 struct player *pp = &player_globals.parray[p];
1820 if (pp->simul_info == NULL) {
1821 pprintf(p, "You are not giving a simul.\n");
1825 if (!pp->simul_info->numBoards) {
1826 pprintf(p, "You are not giving a simul.\n");
1829 decline_withdraw_offers(p, -1, -PEND_SIMUL,DO_DECLINE);
1830 game_ended(pp->simul_info->boards[pp->simul_info->onBoard],
1835 int com_simallabort(int p, param_list param)
1837 struct player *pp = &player_globals.parray[p];
1840 if (pp->simul_info == NULL) {
1841 pprintf(p, "You are not giving a simul.\n");
1845 if (!pp->simul_info->numBoards) {
1846 pprintf(p, "You are not giving a simul.\n");
1850 decline_withdraw_offers(p, -1, -PEND_SIMUL,DO_DECLINE);
1851 for (i = 0; i < pp->simul_info->numBoards; i++)
1852 if (pp->simul_info->boards[i] >= 0)
1853 game_ended(pp->simul_info->boards[i],
1859 int com_simadjourn(int p, param_list param)
1861 struct player *pp = &player_globals.parray[p];
1863 if (pp->simul_info == NULL) {
1864 pprintf(p, "You are not giving a simul.\n");
1868 if (!pp->simul_info->numBoards) {
1869 pprintf(p, "You are not giving a simul.\n");
1872 decline_withdraw_offers(p, -1, -PEND_SIMUL,DO_DECLINE);
1873 game_ended(pp->simul_info->boards[pp->simul_info->onBoard],
1874 WHITE, END_ADJOURN);
1878 int com_simalladjourn(int p, param_list param)
1880 struct player *pp = &player_globals.parray[p];
1883 if (pp->simul_info == NULL) {
1884 pprintf(p, "You are not giving a simul.\n");
1888 if (!pp->simul_info->numBoards) {
1889 pprintf(p, "You are not giving a simul.\n");
1892 decline_withdraw_offers(p, -1, -PEND_SIMUL,DO_DECLINE);
1893 for (i = 0; i < pp->simul_info->numBoards; i++)
1894 if (pp->simul_info->boards[i] >= 0)
1895 game_ended(pp->simul_info->boards[i],
1896 WHITE, END_ADJOURN);
1901 int com_moretime(int p, param_list param)
1903 struct player *pp = &player_globals.parray[p];
1906 if ((pp->game >=0) &&((game_globals.garray[pp->game].status == GAME_EXAMINE) ||
1907 (game_globals.garray[pp->game].status == GAME_SETUP))) {
1908 pprintf(p, "You cannot use moretime in an examined game.\n");
1911 increment = param[0].val.integer;
1912 if (increment <= 0) {
1913 pprintf(p, "Moretime requires an integer value greater than zero.\n");
1919 if (increment > 600) {
1920 pprintf(p, "Moretime has a maximum limit of 600 seconds.\n");
1924 if (game_globals.garray[g].white == p) {
1925 game_globals.garray[g].bTime += increment * 10;
1926 game_globals.garray[g].bRealTime += increment * 10 * 100;
1927 pprintf(p, "%d seconds were added to your opponents clock\n",
1929 pprintf_prompt(pp->opponent,
1930 "\nYour opponent has added %d seconds to your clock.\n",
1933 if (game_globals.garray[g].black == p) {
1934 game_globals.garray[g].wTime += increment * 10;;
1935 game_globals.garray[g].wRealTime += increment * 10 * 100;
1936 pprintf(p, "%d seconds were added to your opponents clock\n",
1938 pprintf_prompt(pp->opponent,
1939 "\nYour opponent has added %d seconds to your clock.\n",