aboutsummaryrefslogtreecommitdiffstats
path: root/FICS/gameproc.c.orig
diff options
context:
space:
mode:
Diffstat (limited to 'FICS/gameproc.c.orig')
-rw-r--r--FICS/gameproc.c.orig2826
1 files changed, 2826 insertions, 0 deletions
diff --git a/FICS/gameproc.c.orig b/FICS/gameproc.c.orig
new file mode 100644
index 0000000..832f5c9
--- /dev/null
+++ b/FICS/gameproc.c.orig
@@ -0,0 +1,2826 @@
+/* gameproc.c
+ *
+ */
+
+/*
+ fics - An internet chess server.
+ Copyright (C) 1993 Richard V. Nash
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+/* Revision history:
+ name email yy/mm/dd Change
+ Richard Nash 93/10/22 Created
+*/
+
+#include "stdinclude.h"
+
+#include "common.h"
+#include "command.h"
+#include "ficsmain.h"
+#include "config.h"
+#include "playerdb.h"
+#include "gamedb.h"
+#include "gameproc.h"
+#include "movecheck.h"
+#include "utils.h"
+#include "ratings.h"
+#include "rmalloc.h"
+#include "comproc.h"
+#include "matchproc.h"
+#include "formula.h"
+#include "eco.h"
+#include "network.h"
+/* #include "hostinfo.h" */
+
+PUBLIC void game_ended(int g, int winner, int why)
+{
+ char outstr[200];
+ char tmp[200];
+ int p;
+ int rate_change = 0;
+ int isDraw = 0;
+ int whiteResult;
+ char winSymbol[10];
+ char EndSymbol[10];
+ char *NameOfWinner, *NameOfLoser;
+ int beingplayed = 0; /* i.e. it wasn't loaded for adjudication */
+
+ beingplayed = (parray[garray[g].black].game == g);
+
+ sprintf(outstr, "\n{Game %d (%s vs. %s) ", g + 1,
+ parray[garray[g].white].name,
+ parray[garray[g].black].name);
+ garray[g].result = why;
+ garray[g].winner = winner;
+ if (winner == WHITE) {
+ whiteResult = RESULT_WIN;
+ strcpy(winSymbol, "1-0");
+ NameOfWinner = parray[garray[g].white].name;
+ NameOfLoser = parray[garray[g].black].name;
+ } else {
+ whiteResult = RESULT_LOSS;
+ strcpy(winSymbol, "0-1");
+ NameOfWinner = parray[garray[g].black].name;
+ NameOfLoser = parray[garray[g].white].name;
+ }
+ switch (why) {
+ case END_CHECKMATE:
+ sprintf(tmp, "%s checkmated} %s\n", NameOfLoser, winSymbol);
+ strcpy(EndSymbol, "Mat");
+ rate_change = 1;
+ break;
+ case END_RESIGN:
+ sprintf(tmp, "%s resigns} %s\n", NameOfLoser, winSymbol);
+ strcpy(EndSymbol, "Res");
+ rate_change = 1;
+ break;
+ case END_FLAG:
+ sprintf(tmp, "%s forfeits on time} %s\n", NameOfLoser, winSymbol);
+ strcpy(EndSymbol, "Fla");
+ rate_change = 1;
+ break;
+ case END_STALEMATE:
+ sprintf(tmp, "Game drawn by stalemate} 1/2-1/2\n");
+ isDraw = 1;
+ strcpy(EndSymbol, "Sta");
+ rate_change = 1;
+ whiteResult = RESULT_DRAW;
+ break;
+ case END_AGREEDDRAW:
+ sprintf(tmp, "Game drawn by mutual agreement} 1/2-1/2\n");
+ isDraw = 1;
+ strcpy(EndSymbol, "Agr");
+ rate_change = 1;
+ whiteResult = RESULT_DRAW;
+ break;
+ case END_BOTHFLAG:
+ sprintf(tmp, "Game drawn because both players ran out of time} 1/2-1/2\n");
+ isDraw = 1;
+ strcpy(EndSymbol, "Fla");
+ rate_change = 1;
+ whiteResult = RESULT_DRAW;
+ break;
+ case END_REPETITION:
+ sprintf(tmp, "Game drawn by repetition} 1/2-1/2\n");
+ isDraw = 1;
+ strcpy(EndSymbol, "Rep");
+ rate_change = 1;
+ whiteResult = RESULT_DRAW;
+ break;
+ case END_50MOVERULE:
+ sprintf(tmp, "Game drawn by the 50 move rule} 1/2-1/2\n");
+ isDraw = 1;
+ strcpy(EndSymbol, "50");
+ rate_change = 1;
+ whiteResult = RESULT_DRAW;
+ break;
+ case END_ADJOURN:
+ sprintf(tmp, "Game adjourned by mutual agreement} *\n");
+ game_save(g);
+ break;
+ case END_LOSTCONNECTION:
+ sprintf(tmp, "%s lost connection; game ", NameOfWinner);
+ if (parray[garray[g].white].registered && parray[garray[g].black].registered) {
+ sprintf(tmp, "adjourned} *\n");
+ game_save(g);
+ } else
+ sprintf(tmp, "aborted} *\n");
+ whiteResult = RESULT_ABORT;
+ break;
+ case END_ABORT:
+ sprintf(tmp, "Game aborted by mutual agreement} *\n");
+ whiteResult = RESULT_ABORT;
+ break;
+ case END_COURTESY:
+ sprintf(tmp, "Game courtesyaborted by %s} *\n", NameOfWinner);
+ whiteResult = RESULT_ABORT;
+ break;
+ case END_COURTESYADJOURN:
+ sprintf(tmp, "Game courtesyadjourned by %s} *\n", NameOfWinner);
+ game_save(g);
+ break;
+ case END_NOMATERIAL:
+ /* Draw by insufficient material (e.g., lone K vs. lone K) */
+ sprintf(tmp, "Neither player has mating material} 1/2-1/2\n");
+ isDraw = 1;
+ strcpy(EndSymbol, "NM ");
+ rate_change = 1;
+ whiteResult = RESULT_DRAW;
+ break;
+ case END_FLAGNOMATERIAL:
+ sprintf(tmp, "%s ran out of time and %s has no material to mate} 1/2-1/2\n",
+ NameOfLoser, NameOfWinner);
+ isDraw = 1;
+ strcpy(EndSymbol, "TM ");
+ rate_change = 1;
+ whiteResult = RESULT_DRAW;
+ break;
+ case END_ADJWIN:
+ sprintf(tmp, "%s wins by adjudication} %s\n", NameOfWinner, winSymbol);
+ strcpy(EndSymbol, "Adj");
+ rate_change = 1;
+ break;
+ case END_ADJDRAW:
+ sprintf(tmp, "Game drawn by adjudication} 1/2-1/2\n");
+ isDraw = 1;
+ strcpy(EndSymbol, "Adj");
+ rate_change = 1;
+ whiteResult = RESULT_DRAW;
+ break;
+ case END_ADJABORT:
+ sprintf(tmp, "Game aborted by adjudication} *\n");
+ whiteResult = RESULT_ABORT;
+ break;
+ default:
+ sprintf(tmp, "Hmm, the game ended and I don't know why} *\n");
+ break;
+ }
+ strcat(outstr, tmp);
+ if (beingplayed) {
+ pprintf_noformat(garray[g].white, outstr);
+ pprintf_noformat(garray[g].black, outstr);
+
+ for (p = 0; p < p_num; p++) {
+ if ((p == garray[g].white) || (p == garray[g].black))
+ continue;
+ if (parray[p].status != PLAYER_PROMPT)
+ continue;
+ if (!parray[p].i_game && !player_is_observe(p, g))
+ continue;
+ pprintf_noformat(p, outstr);
+ pprintf_prompt(p, "");
+ }
+ }
+ if ((garray[g].rated) && (rate_change)) {
+ /* Adjust ratings */
+ rating_update(g);
+ if (parray[garray[g].white].network_player &&
+ parray[garray[g].black].network_player) {
+ if (MailGameResult) { /* Send to ratings server */
+ if (isDraw) {
+ /* hostinfo_mailresults(garray[g].type == TYPE_BLITZ ? "blitz" :
+ garray[g].type == TYPE_WILD ? "wild " : "stand", "
+ parray[garray[g].white].name, parray[garray[g].black].name,
+ "draw"); */
+ } else {
+/* hostinfo_mailresults(garray[g].type == TYPE_BLITZ ? "blitz" : garray[g].type == TYPE_WILD ? "wild " : "stand",
+ parray[garray[g].white].name,
+ parray[garray[g].black].name,
+ (winner == WHITE) ? parray[garray[g].white].name :
+ parray[garray[g].black].name); */
+ }
+ }
+ }
+ } else {
+ if (beingplayed) {
+ pprintf(garray[g].white, "No ratings adjustment done.\n");
+ pprintf(garray[g].black, "No ratings adjustment done.\n");
+ }
+ }
+ if (rate_change)
+ game_write_complete(g, isDraw, EndSymbol);
+ /* Mail off the moves */
+ if (parray[garray[g].white].automail) {
+ pcommand(garray[g].white, "mailmoves");
+ }
+ if (parray[garray[g].black].automail) {
+ pcommand(garray[g].black, "mailmoves");
+ }
+ parray[garray[g].white].num_white++;
+ parray[garray[g].white].lastColor = WHITE;
+ parray[garray[g].black].num_black++;
+ parray[garray[g].black].lastColor = BLACK;
+ parray[garray[g].white].last_opponent = garray[g].black;
+ parray[garray[g].black].last_opponent = garray[g].white;
+ if (beingplayed) {
+ parray[garray[g].white].game = -1;
+ parray[garray[g].black].game = -1;
+ parray[garray[g].white].opponent = -1;
+ parray[garray[g].black].opponent = -1;
+ if (garray[g].white != commanding_player)
+ pprintf_prompt(garray[g].white, "");
+ if (garray[g].black != commanding_player)
+ pprintf_prompt(garray[g].black, "");
+ if (parray[garray[g].white].simul_info.numBoards) {
+ player_simul_over(garray[g].white, g, whiteResult);
+ }
+ }
+ game_finish(g);
+}
+
+PUBLIC void process_move(int p, char *command)
+{
+ int g;
+ move_t move;
+ int result;
+ unsigned now;
+ int len; /* loon: for lame promotion hack */
+ int i;
+
+ if (parray[p].game <0) {
+ pprintf(p, "You are not playing a game.\n");
+ return;
+ }
+ player_decline_offers(p, -1, -PEND_SIMUL);
+ g = parray[p].game;
+
+ if (garray[g].status != GAME_EXAMINE) {
+ if (parray[p].side != garray[g].game_state.onMove) {
+ pprintf(p, "It is not your move.\n");
+ return;
+ }
+ if (garray[g].clockStopped) {
+ pprintf(p, "Game clock is paused, use \"unpause\" to resume.\n");
+ return;
+ }
+ }
+ if ((len = strlen(command)) > 1) {
+ if (command[len - 2] == '=') {
+ switch (tolower(command[strlen(command) - 1])) {
+ case 'n':
+ parray[p].promote = KNIGHT;
+ break;
+ case 'b':
+ parray[p].promote = BISHOP;
+ break;
+ case 'r':
+ parray[p].promote = ROOK;
+ break;
+ case 'q':
+ parray[p].promote = QUEEN;
+ break;
+ default:
+ pprintf(p, "Don't understand that move.\n");
+ return;
+ break;
+ }
+ }
+ }
+ switch (parse_move(command, &garray[g].game_state, &move, parray[p].promote)) {
+ case MOVE_ILLEGAL:
+ pprintf(p, "Illegal move.\n");
+ return;
+ break;
+ case MOVE_AMBIGUOUS:
+ pprintf(p, "Ambiguous move.\n");
+ return;
+ break;
+ default:
+ break;
+ }
+
+ if (garray[g].status == GAME_EXAMINE) {
+ garray[g].numHalfMoves++;
+ if (garray[g].numHalfMoves > garray[g].examMoveListSize) {
+ garray[g].examMoveListSize += 20; /* Allocate 20 moves at a time */
+ if (!garray[g].examMoveList) {
+ garray[g].examMoveList = (move_t *) rmalloc(sizeof(move_t) * garray[g].examMoveListSize);
+ } else {
+ garray[g].examMoveList = (move_t *) rrealloc(garray[g].examMoveList, sizeof(move_t) * garray[g].examMoveListSize);
+ }
+ }
+ result = execute_move(&garray[g].game_state, &move, 1);
+ move.atTime = now;
+ move.tookTime = 0;
+ garray[g].examMoveList[garray[g].numHalfMoves - 1] = move;
+ /* roll back time */
+ if (garray[g].game_state.onMove == WHITE) {
+ garray[g].wTime += (garray[g].lastDecTime - garray[g].lastMoveTime);
+ } else {
+ garray[g].bTime += (garray[g].lastDecTime - garray[g].lastMoveTime);
+ }
+ now = tenth_secs();
+ if (garray[g].numHalfMoves == 0)
+ garray[g].timeOfStart = now;
+ garray[g].lastMoveTime = now;
+ garray[g].lastDecTime = now;
+
+ } else { /* real game */
+ i = parray[p].opponent;
+ if (parray[i].simul_info.numBoards &&
+ (parray[i].simul_info.boards[parray[i].simul_info.onBoard] != g)) {
+ pprintf(p, "It isn't your turn: wait until the simul giver is at your board.\n");
+ return;
+ }
+#ifdef TIMESEAL
+
+
+ if (con[parray[p].socket].timeseal) { /* does he use timeseal? */
+ if (parray[p].side == WHITE) {
+ garray[g].wLastRealTime = garray[g].wRealTime;
+ garray[g].wTimeWhenMoved = con[parray[p].socket].time;
+ if (((garray[g].wTimeWhenMoved - garray[g].wTimeWhenReceivedMove) < 0) ||
+ (garray[g].wTimeWhenReceivedMove == 0)) {
+ /* might seem weird - but could be caused by a person moving BEFORE
+ he receives the board pos (this is possible due to lag) but it's
+ safe to say he moved in 0 secs :-) */
+ garray[g].wTimeWhenReceivedMove = garray[g].wTimeWhenMoved;
+ } else {
+ garray[g].wRealTime -= garray[g].wTimeWhenMoved - garray[g].wTimeWhenReceivedMove;
+ }
+ } else if (parray[p].side == BLACK) {
+ garray[g].bLastRealTime = garray[g].bRealTime;
+ garray[g].bTimeWhenMoved = con[parray[p].socket].time;
+ if (((garray[g].bTimeWhenMoved - garray[g].bTimeWhenReceivedMove) < 0) ||
+ (garray[g].bTimeWhenReceivedMove == 0)) {
+ /* might seem weird - but could be caused by a person moving BEFORE
+ he receives the board pos (this is possible due to lag) but it's
+ safe to say he moved in 0 secs :-) */
+ garray[g].bTimeWhenReceivedMove = garray[g].bTimeWhenMoved;
+ } else {
+ garray[g].bRealTime -= garray[g].bTimeWhenMoved - garray[g].bTimeWhenReceivedMove;
+ }
+ }
+ }
+ if (parray[p].side == WHITE) {
+ /* we need to reset the opp's time for receiving the board since the
+ timeseal decoder only alters the time if it's 0 Otherwise the time
+ would be changed if the player did a refresh which would screw up
+ the timings */
+ garray[g].bTimeWhenReceivedMove = 0;
+ } else {
+ /* we need to reset the opp's time for receiving the board since the
+ timeseal decoder only alters the time if it's 0 Otherwise the time
+ would be changed if the player did a refresh which would screw up
+ the timings */
+ garray[g].wTimeWhenReceivedMove = 0;
+ }
+
+#endif
+
+ game_update_time(g);
+
+ /* maybe add autoflag here in the future? */
+
+#ifdef TIMESEAL
+
+ if (con[parray[p].socket].timeseal) { /* does he use timeseal? */
+ if (parray[p].side == WHITE) {
+ garray[g].wRealTime += garray[g].wIncrement * 100;
+ garray[g].wTime = garray[g].wRealTime / 100; /* remember to conv to
+ tenth secs */
+ } else if (parray[p].side == BLACK) {
+ garray[g].bRealTime += garray[g].bIncrement * 100; /* conv to ms */
+ garray[g].bTime = garray[g].bRealTime / 100; /* remember to conv to
+ tenth secs */
+ }
+ } else {
+ if (garray[g].game_state.onMove == BLACK) {
+ garray[g].bTime += garray[g].bIncrement;
+ }
+ if (garray[g].game_state.onMove == WHITE) {
+ garray[g].wTime += garray[g].wIncrement;
+ }
+ }
+
+#else
+
+ if (garray[g].game_state.onMove == BLACK) {
+ garray[g].bTime += garray[g].bIncrement;
+ }
+ if (garray[g].game_state.onMove == WHITE) {
+ garray[g].wTime += garray[g].wIncrement;
+ }
+#endif
+
+ /* Do the move */
+ garray[g].numHalfMoves++;
+ if (garray[g].numHalfMoves > garray[g].moveListSize) {
+ garray[g].moveListSize += 20; /* Allocate 20 moves at a time */
+ if (!garray[g].moveList) {
+ garray[g].moveList = (move_t *) rmalloc(sizeof(move_t) * garray[g].moveListSize);
+ } else {
+ garray[g].moveList = (move_t *) rrealloc(garray[g].moveList, sizeof(move_t) * garray[g].moveListSize);
+ }
+ }
+ result = execute_move(&garray[g].game_state, &move, 1);
+ now = tenth_secs();
+ move.atTime = now;
+ if (garray[g].numHalfMoves > 1) {
+ move.tookTime = move.atTime - garray[g].lastMoveTime;
+ } else {
+ move.tookTime = move.atTime - garray[g].startTime;
+ }
+ garray[g].lastMoveTime = now;
+ garray[g].lastDecTime = now;
+
+#ifdef TIMESEAL
+
+ if (con[parray[p].socket].timeseal) { /* does he use timeseal? */
+ if (parray[p].side == WHITE) {
+ move.tookTime = (garray[parray[p].game].wTimeWhenMoved -
+ garray[parray[p].game].wTimeWhenReceivedMove) / 100;
+ } else {
+ move.tookTime = (garray[parray[p].game].bTimeWhenMoved -
+ garray[parray[p].game].bTimeWhenReceivedMove) / 100;
+ }
+ }
+#endif
+
+ garray[g].moveList[garray[g].numHalfMoves - 1] = move;
+ }
+
+ send_boards(g);
+
+ strcpy(garray[g].boardList[garray[g].numHalfMoves], boardToFEN(g));
+
+ if (result == MOVE_ILLEGAL) {
+ pprintf(p, "Internal error, illegal move accepted!\n");
+ }
+ if ((result == MOVE_OK) && (garray[g].status == GAME_EXAMINE)) {
+ int p1;
+
+ for (p1 = 0; p1 < p_num; p1++) {
+ if (parray[p1].status != PLAYER_PROMPT)
+ continue;
+ if (player_is_observe(p1, g) || parray[p1].game == g) {
+ pprintf_prompt(p1, "%s moves: %s\n", parray[p].name, move.algString);
+ }
+ }
+ }
+ if (result == MOVE_CHECKMATE) {
+ if (garray[g].status == GAME_EXAMINE) {
+ int p1;
+
+ for (p1 = 0; p1 < p_num; p1++) {
+ if (parray[p1].status != PLAYER_PROMPT)
+ continue;
+ if (player_is_observe(p1, g) || parray[p1].game == g) {
+ pprintf(p1, "%s has been checkmated.\n",
+ (CToggle(garray[g].game_state.onMove) == BLACK) ? "White" : "Black");
+ }
+ }
+ } else {
+ game_ended(g, CToggle(garray[g].game_state.onMove), END_CHECKMATE);
+ }
+ }
+ if (result == MOVE_STALEMATE) {
+ if (garray[g].status == GAME_EXAMINE) {
+ int p1;
+
+ for (p1 = 0; p1 < p_num; p1++) {
+ if (parray[p1].status != PLAYER_PROMPT)
+ continue;
+ if (player_is_observe(p1, g) || parray[p1].game == g) {
+ pprintf(p1, "Stalemate.\n");
+ }
+ }
+ } else {
+ game_ended(g, CToggle(garray[g].game_state.onMove), END_STALEMATE);
+ }
+ }
+ if (result == MOVE_NOMATERIAL) {
+ if (garray[g].status == GAME_EXAMINE) {
+ int p1;
+
+ for (p1 = 0; p1 < p_num; p1++) {
+ if (parray[p1].status != PLAYER_PROMPT)
+ continue;
+ if (player_is_observe(p1, g) || parray[p1].game == g) {
+ pprintf(p1, "No mating material.\n");
+ }
+ }
+ } else {
+ game_ended(g, CToggle(garray[g].game_state.onMove), END_NOMATERIAL);
+ }
+ }
+}
+
+int GameNumFromParam(int p, int *p1, parameter *param)
+{
+ if (param->type == TYPE_WORD) {
+ *p1 = player_find_part_login(param->val.word);
+ if (*p1 < 0) {
+ pprintf(p, "No user named \"%s\" is logged in.\n", param->val.word);
+ return -1;
+ }
+ if (parray[*p1].game <0)
+ pprintf(p, "%s is not playing a game.\n", parray[*p1].name);
+ return parray[*p1].game;
+ } else { /* Must be an integer */
+ *p1 = -1;
+ if (param->val.integer <= 0)
+ pprintf(p, "%d is not a valid game number.\n", param->val.integer);
+ return param->val.integer - 1;
+ }
+}
+
+PUBLIC int com_resign(int p, param_list param)
+{
+ int g, o, oconnected, confused = 0;
+
+ if (param[0].type == TYPE_NULL) {
+ g = parray[p].game;
+ if ((g < 0) || (garray[g].status == GAME_EXAMINE)) {
+ pprintf(p, "You are not playing a game.\n");
+ } else {
+ player_decline_offers(p, -1, -1);
+ game_ended(g, (garray[g].white == p) ? BLACK : WHITE, END_RESIGN);
+ }
+ } else if (FindPlayer(p, &param[0], &o, &oconnected)) {
+ g = game_new();
+ if (game_read(g, p, o) < 0) {
+ if (game_read(g, o, p) < 0) {
+ confused = 1;
+ pprintf(p, "You have no stored game with %s\n", parray[o].name);
+ } else {
+ garray[g].white = o;
+ garray[g].black = p;
+ }
+ } else {
+ garray[g].white = p;
+ garray[g].black = o;
+ }
+ if (!confused) {
+ pprintf(p, "You resign your stored game with %s\n", parray[o].name);
+ game_delete(garray[g].white, garray[g].black);
+ game_ended(g, (garray[g].white == p) ? BLACK : WHITE, END_RESIGN);
+ pcommand(p, "message %s I have resigned our stored game \"%s vs. %s.\"",
+ parray[o].name,
+ parray[garray[g].white].name,
+ parray[garray[g].black].name);
+ if (!oconnected)
+ player_remove(o);
+ }
+ }
+ return COM_OK;
+}
+
+/*
+PUBLIC int com_resign(int p, param_list param)
+{
+ ASSERT(param[0].type == TYPE_NULL);
+ if ((parray[p].game <0) || (garray[parray[p].game].status == GAME_EXAMINE)) {
+ pprintf(p, "You are not playing a game.\n");
+ return COM_OK;
+ }
+ player_decline_offers(p, -1, -1);
+ game_ended(parray[p].game, (garray[parray[p].game].white == p) ? BLACK : WHITE, END_RESIGN);
+ return COM_OK;
+}
+*/
+
+PUBLIC int com_draw(int p, param_list param)
+{
+ int p1;
+ int move_num = 0;
+ int i = 0, flag = 0;
+
+ ASSERT(param[0].type == TYPE_NULL);
+ if ((parray[p].game <0) ||(garray[parray[p].game].status == GAME_EXAMINE)) {
+ pprintf(p, "You are not playing a game.\n");
+ return COM_OK;
+ }
+ if (garray[parray[p].game].numHalfMoves - ((garray[parray[p].game].game_state.lastIrreversable == -1) ? 0 : garray[parray[p].game].game_state.lastIrreversable) > 99) {
+ game_ended(parray[p].game, (garray[parray[p].game].white == p) ? BLACK : WHITE, END_50MOVERULE);
+ return COM_OK;
+ }
+ if (garray[parray[p].game].game_state.lastIrreversable != -1)
+ move_num = garray[parray[p].game].game_state.lastIrreversable;
+
+ for (i = (garray[parray[p].game].numHalfMoves - 1); i <= garray[parray[p].game].numHalfMoves; i++) {
+ flag = 0;
+ if (garray[parray[p].game].game_state.lastIrreversable != -1)
+ move_num = garray[parray[p].game].game_state.lastIrreversable;
+ for (; move_num <= garray[parray[p].game].numHalfMoves; move_num++) {
+ if ((strlen(garray[parray[p].game].boardList[move_num])) !=
+ (strlen(garray[parray[p].game].boardList[i])))
+ continue;
+
+ if (!strcmp(garray[parray[p].game].boardList[move_num],
+ garray[parray[p].game].boardList[i]))
+ flag++;
+ }
+ if (flag >= 3) {
+ if (player_find_pendfrom(p, parray[p].opponent, PEND_DRAW) >= 0) {
+ player_remove_request(parray[p].opponent, p, PEND_DRAW);
+ player_decline_offers(p, -1, -1);
+ }
+ game_ended(parray[p].game, (garray[parray[p].game].white == p) ? BLACK : WHITE, END_REPETITION);
+ return COM_OK;
+ }
+ }
+
+ p1 = parray[p].opponent;
+ if (parray[p1].simul_info.numBoards &&
+ parray[p1].simul_info.boards[parray[p1].simul_info.onBoard] !=
+ parray[p].game) {
+ pprintf(p, "You can only make requests when the simul player is at your board.\n");
+ return COM_OK;
+ }
+ if (player_find_pendfrom(p, parray[p].opponent, PEND_DRAW) >= 0) {
+ player_remove_request(parray[p].opponent, p, PEND_DRAW);
+ player_decline_offers(p, -1, -1);
+ game_ended(parray[p].game, (garray[parray[p].game].white == p) ? BLACK : WHITE, END_AGREEDDRAW);
+ } else {
+ pprintf(parray[p].opponent, "\n");
+ pprintf_highlight(parray[p].opponent, "%s", parray[p].name);
+ pprintf_prompt(parray[p].opponent, " offers you a draw.\n");
+ pprintf(p, "Draw request sent.\n");
+ player_add_request(p, parray[p].opponent, PEND_DRAW, 0);
+ }
+ return COM_OK;
+}
+
+PUBLIC int com_pause(int p, param_list param)
+{
+ int g;
+ int now;
+
+ ASSERT(param[0].type == TYPE_NULL);
+ if ((parray[p].game <0) ||(garray[parray[p].game].status == GAME_EXAMINE)) {
+ pprintf(p, "You are not playing a game.\n");
+ return COM_OK;
+ }
+ g = parray[p].game;
+ if (garray[g].wTime == 0) {
+ pprintf(p, "You can't pause untimed games.\n");
+ return COM_OK;
+ }
+ if (garray[g].clockStopped) {
+ pprintf(p, "Game is already paused, use \"unpause\" to resume.\n");
+ return COM_OK;
+ }
+ if (player_find_pendfrom(p, parray[p].opponent, PEND_PAUSE) >= 0) {
+ player_remove_request(parray[p].opponent, p, PEND_PAUSE);
+ garray[g].clockStopped = 1;
+ /* Roll back the time */
+ if (garray[g].game_state.onMove == WHITE) {
+ garray[g].wTime += (garray[g].lastDecTime - garray[g].lastMoveTime);
+ } else {
+ garray[g].bTime += (garray[g].lastDecTime - garray[g].lastMoveTime);
+ }
+ now = tenth_secs();
+ if (garray[g].numHalfMoves == 0)
+ garray[g].timeOfStart = now;
+ garray[g].lastMoveTime = now;
+ garray[g].lastDecTime = now;
+ send_boards(g);
+ pprintf_prompt(parray[p].opponent, "\n%s accepted pause. Game clock paused.\n",
+ parray[p].name);
+ pprintf(p, "Game clock paused.\n");
+ } else {
+ pprintf(parray[p].opponent, "\n");
+ pprintf_highlight(parray[p].opponent, "%s", parray[p].name);
+ pprintf_prompt(parray[p].opponent, " requests to pause the game.\n");
+ pprintf(p, "Pause request sent.\n");
+ player_add_request(p, parray[p].opponent, PEND_PAUSE, 0);
+ }
+ return COM_OK;
+}
+
+PUBLIC int com_unpause(int p, param_list param)
+{
+ int now;
+ int g;
+
+ ASSERT(param[0].type == TYPE_NULL);
+ if ((parray[p].game <0) ||(garray[parray[p].game].status == GAME_EXAMINE)) {
+ pprintf(p, "You are not playing a game.\n");
+ return COM_OK;
+ }
+ g = parray[p].game;
+ if (!garray[g].clockStopped) {
+ pprintf(p, "Game is not paused.\n");
+ return COM_OK;
+ }
+ garray[g].clockStopped = 0;
+ now = tenth_secs();
+ if (garray[g].numHalfMoves == 0)
+ garray[g].timeOfStart = now;
+ garray[g].lastMoveTime = now;
+ garray[g].lastDecTime = now;
+ send_boards(g);
+ pprintf(p, "Game clock resumed.\n");
+ pprintf_prompt(parray[p].opponent, "\nGame clock resumed.\n");
+ return COM_OK;
+}
+
+PUBLIC int com_abort(int p, param_list param)
+{
+ int p1, g, myColor, yourColor;
+
+ ASSERT(param[0].type == TYPE_NULL);
+
+ g = parray[p].game;
+ if ((g < 0) || (garray[parray[p].game].status == GAME_EXAMINE)) {
+ pprintf(p, "You are not playing a game.\n");
+ return COM_OK;
+ }
+ p1 = parray[p].opponent;
+ myColor = (p == garray[g].white ? WHITE : BLACK);
+ yourColor = (myColor == WHITE ? BLACK : WHITE);
+
+ if (parray[p1].simul_info.numBoards &&
+ parray[p1].simul_info.boards[parray[p1].simul_info.onBoard] != g) {
+ pprintf(p, "You can only make requests when the simul player is at your board.\n");
+ return COM_OK;
+ }
+ if (player_find_pendfrom(p, p1, PEND_ABORT) >= 0) {
+ player_remove_request(p1, p, PEND_ABORT);
+ player_decline_offers(p, -1, -1);
+ game_ended(g, yourColor, END_ABORT);
+ } else {
+ game_update_time(g);
+
+#ifdef TIMESEAL
+
+ if (con[parray[parray[p].opponent].socket].timeseal) { /* opp uses timeseal? */
+
+ /* If opponent has timeseal - we have no use for courtesyabort since
+ courtesyabort was used when opponent lagged out of time which cannot
+ happen with timeseal - only courtesyadjourn should be possible.
+ Thus: the request can only be for a normal abort of the game. */
+
+ pprintf(p1, "\n");
+ pprintf_highlight(p1, "%s", parray[p].name);
+ pprintf_prompt(p1, " would like to abort the game.\n");
+ pprintf(p, "Abort request sent.\n");
+ player_add_request(p, p1, PEND_ABORT, 0);
+ } else {
+ if ((myColor == WHITE && garray[g].wTime > 0 && garray[g].bTime <= 0)
+ || (myColor == BLACK && garray[g].bTime > 0 && garray[g].wTime <= 0)) {
+ /* player wants to abort + opponent is out of time = courtesyabort */
+ pprintf(p, "Since you have time, and your opponent has none, the game has been aborted.");
+ pprintf(p1, "Your opponent has aborted the game rather than calling your flag.");
+ player_decline_offers(p, -1, -1);
+ game_ended(g, myColor, END_COURTESY);
+ } else {
+ pprintf(p1, "\n");
+ pprintf_highlight(p1, "%s", parray[p].name);
+ pprintf_prompt(p1, " would like to abort the game.\n");
+ pprintf(p, "Abort request sent.\n");
+ player_add_request(p, p1, PEND_ABORT, 0);
+ }
+ }
+
+#else
+
+ if ((myColor == WHITE && garray[g].wTime > 0 && garray[g].bTime <= 0)
+ || (myColor == BLACK && garray[g].bTime > 0 && garray[g].wTime <= 0)) {
+ /* player wants to abort + opponent is out of time = courtesyabort */
+ pprintf(p, "Since you have time, and your opponent has none, the game has been aborted.");
+ pprintf(p1, "Your opponent has aborted the game rather than calling your flag.");
+ player_decline_offers(p, -1, -1);
+ game_ended(g, myColor, END_COURTESY);
+ } else {
+ pprintf(p1, "\n");
+ pprintf_highlight(p1, "%s", parray[p].name);
+ pprintf(p1, " would like to abort the game; ");
+ pprintf_prompt(p1, "type \"abort\" to accept.\n");
+ pprintf(p, "Abort request sent.\n");
+ player_add_request(p, p1, PEND_ABORT, 0);
+ }
+
+#endif
+
+ }
+ return COM_OK;
+}
+
+#if 0
+int Courtesy(int p, int type)
+{
+ int g;
+
+ if (parray[p].game <0) {
+ pprintf(p, "You are not playing a game.\n");
+ return COM_OK;
+ }
+ g = parray[p].game;
+ if (garray[g].wInitTime == 0) {
+ if (type == END_COURTESY)
+ pprintf(p, "You can't courtesy abort an untimed game, just resign.\n");
+ else if (type == END_COURTESYADJOURN)
+ pprintf(p, "You can't courtesy adjourn an untimed game, just resign.\n");
+ return COM_OK;
+ }
+ game_update_time(g);
+ if (((garray[g].white == p) && (garray[g].bTime <= 0) && (garray[g].wTime > 0)) ||
+ ((garray[g].black == p) && (garray[g].wTime <= 0) && (garray[g].bTime > 0))) {
+ player_decline_offers(p, -1, -1);
+ game_ended(parray[p].game, (garray[g].white == p) ? WHITE : BLACK, type);
+ } else {
+ if (type == END_COURTESY)
+ pprintf(p, "Game not aborted.\n");
+ else if (type == END_COURTESYADJOURN)
+ pprintf(p, "Game not adjourned.\n");
+ pprintf(p, "Either your opponent still has time, or you are out of time also.\n");
+ }
+ return COM_OK;
+}
+
+PUBLIC int com_courtesyabort(int p, param_list param)
+{
+ ASSERT(param[0].type == TYPE_NULL);
+ return Courtesy(p, END_COURTESY);
+}
+
+PUBLIC int com_courtesyadjourn(int p, param_list param)
+{
+ ASSERT(param[0].type == TYPE_NULL);
+ if (!garray[parray[p].game].rated) {
+ pprintf(p, "You cannot adjourn an unrated game. Use \"courtesyabort\".\n");
+ return COM_OK;
+ }
+ return Courtesy(p, END_COURTESYADJOURN);
+}
+#endif
+
+PUBLIC int com_courtesyabort(int p, param_list param)
+{
+ pprintf(p, "Courtesyabort is obsolete; use \"abort\" instead.\n");
+ return COM_OK;
+}
+
+PUBLIC int com_courtesyadjourn(int p, param_list param)
+{
+ pprintf(p, "Use \"adjourn\" to courtesyadjourn a game.\n");
+ return COM_OK;
+}
+
+PRIVATE int player_has_mating_material(game_state_t *gs, int color)
+{
+ int i, j;
+ int piece;
+ int minor_pieces = 0;
+
+ for (i = 0; i < 8; i++)
+ for (j = 0; j < 8; j++) {
+ piece = gs->board[i][j];
+ switch (piecetype(piece)) {
+ case BISHOP:
+ case KNIGHT:
+ if (iscolor(piece, color))
+ minor_pieces++;
+ break;
+ case KING:
+ case NOPIECE:
+ break;
+ default:
+ if (iscolor(piece, color))
+ return 1;
+ }
+ }
+ return ((minor_pieces > 1) ? 1 : 0);
+}
+
+PUBLIC int com_flag(int p, param_list param)
+{
+ int g;
+ int myColor;
+
+ ASSERT(param[0].type == TYPE_NULL);
+ if ((parray[p].game <0) ||(garray[parray[p].game].status == GAME_EXAMINE)) {
+ pprintf(p, "You are not playing a game.\n");
+ return COM_OK;
+ }
+ g = parray[p].game;
+ myColor = (p == garray[g].white ? WHITE : BLACK);
+ if (garray[g].wInitTime == 0) {
+ pprintf(p, "You can't flag an untimed game.\n");
+ return COM_OK;
+ }
+ if (garray[g].numHalfMoves < 2) {
+ pprintf(p, "You cannot flag if your opponent has not moved.\nYou can use abort instead.\n");
+ return COM_OK;
+ }
+ game_update_time(g);
+
+#ifdef TIMESEAL
+
+ {
+ int wt, bt;
+
+ if (con[parray[p].socket].timeseal) { /* do caller use timeseal? */
+ if (myColor == WHITE) {
+ wt = garray[g].wRealTime;
+ } else {
+ bt = garray[g].bRealTime;
+ }
+ } else {
+ if (myColor == WHITE) {
+ wt = garray[g].wTime;
+ } else {
+ bt = garray[g].bTime;
+ }
+ }
+
+ if (con[parray[parray[p].opponent].socket].timeseal) { /* opp uses timeseal? */
+ if (myColor == WHITE) {
+ bt = garray[g].bRealTime;
+ } else {
+ wt = garray[g].wRealTime;
+ }
+ } else {
+ if (myColor == WHITE) {
+ bt = garray[g].bTime;
+ } else {
+ wt = garray[g].wTime;
+ }
+ }
+
+ /* the clocks to compare is now in wt and bt */
+
+ if ((wt <= 0) && (bt <= 0)) {
+ player_decline_offers(p, -1, -1);
+ game_ended(g, myColor, END_BOTHFLAG);
+ return COM_OK;
+ }
+ if (myColor == WHITE) {
+ if (bt > 0) {
+ pprintf(p, "Your opponent is not out of time!\n");
+ return COM_OK;
+ }
+ } else {
+ if (wt > 0) {
+ pprintf(p, "Your opponent is not out of time!\n");
+ return COM_OK;
+ }
+ }
+ }
+
+#else
+
+ if ((garray[g].wTime <= 0) && (garray[g].bTime <= 0)) {
+ player_decline_offers(p, -1, -1);
+ game_ended(g, myColor, END_BOTHFLAG);
+ return COM_OK;
+ }
+ if (myColor == WHITE) {
+ if (garray[g].bTime > 0) {
+ pprintf(p, "Your opponent is not out of time!\n");
+ return COM_OK;
+ }
+ } else {
+ if (garray[g].wTime > 0) {
+ pprintf(p, "Your opponent is not out of time!\n");
+ return COM_OK;
+ }
+ }
+
+#endif
+
+ player_decline_offers(p, -1, -1);
+ if (player_has_mating_material(&garray[g].game_state, myColor))
+ game_ended(g, myColor, END_FLAG);
+ else
+ game_ended(g, myColor, END_FLAGNOMATERIAL);
+ return COM_OK;
+}
+
+PUBLIC int com_adjourn(int p, param_list param)
+{
+ int p1, g, myColor, yourColor;
+
+ ASSERT(param[0].type == TYPE_NULL);
+ g = parray[p].game;
+ if ((g < 0) || (garray[parray[p].game].status == GAME_EXAMINE)) {
+ pprintf(p, "You are not playing a game.\n");
+ return COM_OK;
+ }
+ p1 = parray[p].opponent;
+ if (!(parray[p].registered && parray[p1].registered)) {
+ pprintf(p, "Both players must be registered to adjorn a game. Use \"abort\".\n");
+ return COM_OK;
+ }
+ myColor = (p == garray[g].white ? WHITE : BLACK);
+ yourColor = (myColor == WHITE ? BLACK : WHITE);
+
+ if (player_find_pendfrom(p, p1, PEND_ADJOURN) >= 0) {
+ player_remove_request(p1, p, PEND_ADJOURN);
+ player_decline_offers(p, -1, -1);
+ game_ended(parray[p].game, yourColor, END_ADJOURN);
+ } else {
+ game_update_time(g);
+ if (((myColor == WHITE) && (garray[g].wTime > 0) && (garray[g].bTime <= 0))
+ || ((myColor == BLACK) && (garray[g].bTime > 0) && (garray[g].wTime <= 0))) {
+/* player wants to adjourn + opponent is out of time = courtesyadjourn */
+ pprintf(p, "Since you have time, and your opponent has none, the game has been adjourned.");
+ pprintf(p1, "Your opponent has adjourned the game rather than calling your flag.");
+ player_decline_offers(p, -1, -1);
+ game_ended(g, myColor, END_COURTESYADJOURN);
+ } else {
+ pprintf(p1, "\n");
+ pprintf_highlight(p1, "%s", parray[p].name);
+ pprintf(p1, " would like to adjourn the game; ");
+ pprintf_prompt(p1, "type \"adjourn\" to accept.\n");
+ pprintf(p, "Adjourn request sent.\n");
+ player_add_request(p, p1, PEND_ADJOURN, 0);
+ }
+ }
+ return COM_OK;
+}
+
+PRIVATE int gamesortfunc(const void *i, const void *j)
+{
+ return (GetRating(&parray[garray[*(int *) i].white], garray[*(int *) i].type) +
+ GetRating(&parray[garray[*(int *) i].black], garray[*(int *) i].type) +
+ ((garray[*(int *) i].status == GAME_EXAMINE) ? 10000 : 0) -
+ GetRating(&parray[garray[*(int *) j].white], garray[*(int *) j].type) -
+ GetRating(&parray[garray[*(int *) j].black], garray[*(int *) j].type) -
+ ((garray[*(int *) j].status == GAME_EXAMINE) ? 10000 : 0));
+}
+
+
+PUBLIC int com_games(int p, param_list param)
+{
+ int i, j;
+ int wp, bp;
+ int ws, bs;
+ int selected = 0;
+ int count = 0;
+ int totalcount;
+ char *s = NULL;
+ int slen = 0;
+ int *sortedgames; /* for qsort */
+
+ totalcount = game_count();
+ if (totalcount == 0) {
+ pprintf(p, "There are no games in progress.\n");
+ } else {
+ sortedgames = rmalloc(totalcount * sizeof(int)); /* for qsort */
+
+ if (param[0].type == TYPE_WORD) {
+ s = param[0].val.word;
+ slen = strlen(s);
+ selected = atoi(s);
+ if (selected < 0)
+ selected = 0;
+ }
+ for (i = 0; i < g_num; i++) {
+ if ((garray[i].status != GAME_ACTIVE) && (garray[i].status != GAME_EXAMINE))
+ continue;
+ if ((selected) && (selected != i + 1))
+ continue; /* not selected game number */
+ wp = garray[i].white;
+ bp = garray[i].black;
+ if ((!selected) && s && strncasecmp(s, garray[i].white_name, slen) &&
+ strncasecmp(s, garray[i].black_name, slen))
+ continue; /* player names did not match */
+ sortedgames[count++] = i;
+ }
+ if (!count)
+ pprintf(p, "No matching games were found (of %d in progress).\n", totalcount);
+ else {
+ qsort(sortedgames, count, sizeof(int), gamesortfunc);
+ pprintf(p, "\n");
+ for (j = 0; j < count; j++) {
+ i = sortedgames[j];
+ wp = garray[i].white;
+ bp = garray[i].black;
+ board_calc_strength(&garray[i].game_state, &ws, &bs);
+ if (garray[i].status != GAME_EXAMINE) {
+ pprintf_noformat(p, "%2d %4s %-11.11s %4s %-10.10s [%c%c%c%3d %3d] ",
+ i + 1,
+ ratstrii(GetRating(&parray[wp],
+ garray[i].type),
+ parray[wp].registered),
+ parray[wp].name,
+ ratstrii(GetRating(&parray[bp],
+ garray[i].type),
+ parray[bp].registered),
+ parray[bp].name,
+ (garray[i].private) ? 'p' : ' ',
+ *bstr[garray[i].type],
+ *rstr[garray[i].rated],
+ garray[i].wInitTime / 600,
+ garray[i].wIncrement / 10);
+ game_update_time(i);
+ pprintf_noformat(p, "%6s -",
+ tenth_str((garray[i].wTime > 0 ? garray[i].wTime : 0), 0));
+ pprintf_noformat(p, "%6s (%2d-%2d) %c: %2d\n",
+ tenth_str((garray[i].bTime > 0 ? garray[i].bTime : 0), 0),
+ ws, bs,
+ (garray[i].game_state.onMove == WHITE) ? 'W' : 'B',
+ garray[i].game_state.moveNum);
+ } else {
+ pprintf_noformat(p, "%2d (Exam. %4d %-11.11s %4d %-10.10s) [%c%c%c%3d %3d] ",
+ i + 1,
+ garray[i].white_rating,
+ garray[i].white_name,
+ garray[i].black_rating,
+ garray[i].black_name,
+ (garray[i].private) ? 'p' : ' ',
+ *bstr[garray[i].type],
+ *rstr[garray[i].rated],
+ garray[i].wInitTime / 600,
+ garray[i].wIncrement / 10);
+ pprintf_noformat(p, "%c: %2d\n",
+ (garray[i].game_state.onMove == WHITE) ? 'W' : 'B',
+ garray[i].game_state.moveNum);
+ }
+ }
+ if (count < totalcount)
+ pprintf(p, "\n %d game%s displayed (of %d in progress).\n", count,
+ (count == 1) ? "" : "s", totalcount);
+ else
+ pprintf(p, "\n %d game%s displayed.\n", totalcount, (totalcount == 1) ? "" : "s");
+ }
+ rfree(sortedgames);
+ }
+ return COM_OK;
+}
+
+PRIVATE int do_observe(int p, int obgame)
+{
+ if ((garray[obgame].private) && (parray[p].adminLevel < ADMIN_ADMIN)) {
+ pprintf(p, "Sorry, game %d is a private game.\n", obgame + 1);
+ return COM_OK;
+ }
+ if ((garray[obgame].white == p) || (garray[obgame].black == p)) {
+ if (garray[obgame].status != GAME_EXAMINE) {
+ pprintf(p, "You cannot observe a game that you are playing.\n");
+ return COM_OK;
+ }
+ }
+ if (player_is_observe(p, obgame)) {
+ pprintf(p, "Removing game %d from observation list.\n", obgame + 1);
+ player_remove_observe(p, obgame);
+ } else {
+ if (!player_add_observe(p, obgame)) {
+ pprintf(p, "You are now observing game %d.\n", obgame + 1);
+ send_board_to(obgame, p);
+ } else {
+ pprintf(p, "You are already observing the maximum number of games.\n");
+ }
+ }
+ return COM_OK;
+}
+
+PUBLIC void unobserveAll(int p)
+{
+ int i;
+
+ for (i = 0; i < parray[p].num_observe; i++) {
+ pprintf(p, "Removing game %d from observation list.\n", parray[p].observe_list[i] + 1);
+ }
+ parray[p].num_observe = 0;
+ return;
+}
+
+PUBLIC int com_unobserve(int p, param_list param)
+{
+ int gNum, p1;
+
+ if (param[0].type == TYPE_NULL) {
+ unobserveAll(p);
+ return COM_OK;
+ }
+ gNum = GameNumFromParam(p, &p1, &param[0]);
+ if (gNum < 0)
+ return COM_OK;
+ if (!player_is_observe(p, gNum)) {
+ pprintf(p, "You are not observing game %d.\n", gNum);
+ } else {
+ player_remove_observe(p, gNum);
+ pprintf(p, "Removing game %d from observation list.\n", gNum + 1);
+ }
+ return COM_OK;
+}
+
+PUBLIC int com_observe(int p, param_list param)
+{
+ int i;
+ int p1, obgame;
+
+ if ((parray[p].game >=0) &&(garray[parray[p].game].status == GAME_EXAMINE)) {
+ pprintf(p, "You are still examining a game.\n");
+ return COM_OK;
+ }
+ if (param[0].type == TYPE_NULL) {
+ unobserveAll(p);
+ return COM_OK;
+ }
+ obgame = GameNumFromParam(p, &p1, &param[0]);
+ if (obgame < 0)
+ return COM_OK;
+
+ if ((obgame >= g_num) || ((garray[obgame].status != GAME_ACTIVE) &&
+ (garray[obgame].status != GAME_EXAMINE))) {
+ pprintf(p, "There is no such game.\n");
+ return COM_OK;
+ }
+ if ((p1 >= 0) && parray[p1].simul_info.numBoards) {
+ for (i = 0; i < parray[p1].simul_info.numBoards; i++)
+ if (parray[p1].simul_info.boards[i] >= 0)
+ do_observe(p, parray[p1].simul_info.boards[i]);
+ } else {
+ do_observe(p, obgame);
+ }
+ return COM_OK;
+}
+
+PUBLIC int com_allobservers(int p, param_list param)
+{
+ int obgame;
+ int p1;
+ int start, end;
+ int g;
+ int first;
+
+ if (param[0].type == TYPE_NULL) {
+ obgame = -1;
+ } else {
+ obgame = GameNumFromParam(p, &p1, &param[0]);
+ if (obgame < 0)
+ return COM_OK;
+ }
+ if (obgame == -1) {
+ start = 0;
+ end = g_num;
+ } else if ((obgame >= g_num) || ((obgame < g_num)
+ && ((garray[obgame].status != GAME_ACTIVE)
+ && (garray[obgame].status != GAME_EXAMINE)))) {
+ pprintf(p, "There is no such game.\n");
+ return COM_OK;
+ } else {
+ start = obgame;
+ end = obgame + 1;
+ }
+
+ /* list games being played */
+
+ for (g = start; g < end; g++) {
+ if ((garray[g].status == GAME_ACTIVE) &&
+ ((parray[p].adminLevel > 0) || (garray[g].private == 0))) {
+ for (first = 1, p1 = 0; p1 < p_num; p1++) {
+ if ((parray[p1].status != PLAYER_EMPTY) && (player_is_observe(p1, g))) {
+ if (first) {
+ pprintf(p, "Observing %2d [%s vs. %s]:",
+ g + 1,
+ parray[garray[g].white].name,
+ parray[garray[g].black].name);
+ first = 0;
+ }
+ pprintf(p, " %s%s", (parray[p1].game >=0) ? "#" : "", parray[p1].name);
+ }
+ }
+ if (!first)
+ pprintf(p, "\n");
+ }
+ }
+
+ /* list games being examined last */
+
+ for (g = start; g < end; g++) {
+ if ((garray[g].status == GAME_EXAMINE) &&
+ ((parray[p].adminLevel > 0) || (garray[g].private == 0))) {
+ for (first = 1, p1 = 0; p1 < p_num; p1++) {
+ if ((parray[p1].status != PLAYER_EMPTY) && (player_is_observe(p1, g) ||
+ (parray[p1].game == g))) {
+ if (first) {
+ if (strcmp(garray[g].white_name, garray[g].black_name)) {
+ pprintf(p, "Examining %2d [%s vs %s]:", g + 1,
+ garray[g].white_name, garray[g].black_name);
+ } else {
+ pprintf(p, "Examining %2d (scratch):", g + 1);
+ }
+ first = 0;
+ }
+ pprintf(p, " %s%s", (parray[p1].game == g) ? "#" : "", parray[p1].name);
+ }
+ }
+ if (!first)
+ pprintf(p, "\n");
+ }
+ }
+ return COM_OK;
+}
+
+PUBLIC int com_unexamine(int p, param_list param)
+{
+ int g, p1, flag = 0;
+
+ if ((parray[p].game <0) ||(garray[parray[p].game].status != GAME_EXAMINE)) {
+ pprintf(p, "You are not examining any games.\n");
+ return COM_OK;
+ }
+ g = parray[p].game;
+ parray[p].game = -1;
+ for (p1 = 0; p1 < p_num; p1++) {
+ if (parray[p1].status != PLAYER_PROMPT)
+ continue;
+ if ((parray[p1].game == g) &&(p != p1)) {
+ /* ok - there are other examiners to take over the game */
+ flag = 1;
+ }
+ if ((player_is_observe(p1, g)) || (parray[p1].game == g)) {
+ pprintf(p1, "%s stopped examining game %d.\n", parray[p].name, g + 1);
+ }
+ }
+ if (!flag) {
+ for (p1 = 0; p1 < p_num; p1++) {
+ if (parray[p1].status != PLAYER_PROMPT)
+ continue;
+ if (player_is_observe(p1, g)) {
+ pprintf(p1, "There are no examiners.\n");
+ pcommand(p1, "unobserve %d", g + 1);
+ }
+ }
+ game_remove(g);
+ }
+ pprintf(p, "You are no longer examining game %d.\n", g + 1);
+ return COM_OK;
+}
+
+PUBLIC int com_mexamine(int p, param_list param)
+{
+ int g, p1, p2;
+
+ if ((parray[p].game <0) ||(garray[parray[p].game].status != GAME_EXAMINE)) {
+ pprintf(p, "You are not examining any games.\n");
+ return COM_OK;
+ }
+ p1 = player_find_part_login(param[0].val.word);
+ if (p1 < 0) {
+ pprintf(p, "No user named \"%s\" is logged in.\n", param[0].val.word);
+ return COM_OK;
+ }
+ g = parray[p].game;
+ if (!player_is_observe(p1, g)) {
+ pprintf(p, "%s must observe the game you are analysing.\n", parray[p1].name);
+ return COM_OK;
+ } else {
+ if (parray[p1].game >=0) {
+ pprintf(p, "%s is already analysing the game.\n", parray[p1].name);
+ return COM_OK;
+ }
+ /* if we get here - let's make him examiner of the game */
+ unobserveAll(p1); /* fix for Xboard */
+ player_decline_offers(p1, -1, PEND_MATCH);
+ player_withdraw_offers(p1, -1, PEND_MATCH);
+ player_withdraw_offers(p1, -1, PEND_SIMUL);
+
+ parray[p1].game = g; /* yep - it really is that easy :-) */
+ pprintf(p1, "You are now examiner of game %d.\n", g + 1);
+ send_board_to(g, p1); /* pos not changed - but fixes Xboard */
+ for (p2 = 0; p2 < p_num; p2++) {
+ if (parray[p2].status != PLAYER_PROMPT)
+ continue;
+ if (p2 == p1)
+ continue;
+ if ((player_is_observe(p2, g)) || (parray[p2].game == g)) {
+ pprintf_prompt(p2, "%s is now examiner of game %d.\n", parray[p1].name, g + 1);
+ }
+ }
+ }
+ return COM_OK;
+}
+
+PUBLIC int com_moves(int p, param_list param)
+{
+ int g;
+ int p1;
+
+ if (param[0].type == TYPE_NULL) {
+ if (parray[p].game >=0) {
+ g = parray[p].game;
+ } else if (parray[p].num_observe) {
+ for (g = 0; g < parray[p].num_observe; g++) {
+ pprintf(p, "%s\n", movesToString(parray[p].observe_list[g], 0));
+ }
+ return COM_OK;
+ } else {
+ pprintf(p, "You are neither playing, observing nor examining a game.\n");
+ return COM_OK;
+ }
+ } else {
+ g = GameNumFromParam(p, &p1, &param[0]);
+ if (g < 0)
+ return COM_OK;
+ }
+ if ((g < 0) || (g >= g_num) || ((garray[g].status != GAME_ACTIVE) &&
+ (garray[g].status != GAME_EXAMINE))) {
+ pprintf(p, "There is no such game.\n");
+ return COM_OK;
+ }
+ if ((garray[g].white != p) && (garray[g].black != p) && (garray[g].private) && (parray[p].adminLevel < ADMIN_ADMIN)) {
+ pprintf(p, "Sorry, that is a private game.\n");
+ return COM_OK;
+ }
+ pprintf(p, "%s\n", movesToString(g, 0)); /* pgn may break interfaces? */
+ return COM_OK;
+}
+
+PUBLIC int com_mailmoves(int p, param_list param)
+{
+ int g;
+ int p1;
+ char subj[81];
+
+ if (!parray[p].registered) {
+ pprintf(p, "Only registered people can use the mailhelp command.\n");
+ return COM_OK;
+ }
+
+ if (param[0].type == TYPE_NULL) {
+ if (parray[p].game >=0) {
+ g = parray[p].game;
+ } else {
+ pprintf(p, "You are neither playing, observing nor examining a game.\n");
+ return COM_OK;
+ }
+ } else {
+ g = GameNumFromParam(p, &p1, &param[0]);
+ if (g < 0)
+ return COM_OK;
+ }
+ if ((g < 0) || (g >= g_num) || ((garray[g].status != GAME_ACTIVE) && (garray[g].status != GAME_EXAMINE))) {
+ pprintf(p, "There is no such game.\n");
+ return COM_OK;
+ }
+ if ((garray[g].white != p) && (garray[g].black != p) && (garray[g].private) && (parray[p].adminLevel < ADMIN_ADMIN)) {
+ pprintf(p, "Sorry, that is a private game.\n");
+ return COM_OK;
+ }
+ sprintf(subj, "FICS game report %s vs %s", garray[g].white_name, garray[g].black_name);
+ if (mail_string_to_user(p, subj, movesToString(g, parray[p].pgn))) {
+ pprintf(p, "Moves NOT mailed, perhaps your address is incorrect.\n");
+ } else {
+ pprintf(p, "Moves mailed.\n");
+ }
+ return COM_OK;
+}
+
+PUBLIC int com_oldmoves(int p, param_list param)
+{
+ int g;
+ int p1 = p;
+
+ if (param[0].type == TYPE_NULL) {
+ p1 = p;
+ } else if (param[0].type == TYPE_WORD) {
+ p1 = player_find_part_login(param[0].val.word);
+ if (p1 < 0) {
+ pprintf(p, "No user named \"%s\" is logged in.\n", param[0].val.word);
+ return COM_OK;
+ }
+ }
+ g = FindOldGameFor(p1);
+ if (g < 0) {
+ pprintf(p, "There is no old game for %s.\n", parray[p1].name);
+ return COM_OK;
+ }
+ if ((garray[g].white != p) && (garray[g].black != p) && (garray[g].private) && (parray[p].adminLevel < ADMIN_ADMIN)) {
+ pprintf(p, "Sorry, that is a private game.\n");
+ return COM_OK;
+ }
+ pprintf(p, "%s\n", movesToString(g, 0)); /* pgn may break interfaces? */
+ return COM_OK;
+}
+
+PUBLIC int com_mailoldmoves(int p, param_list param)
+{
+ int g;
+ int p1 = p;
+ char subj[81];
+
+ if (!parray[p].registered) {
+ pprintf(p, "Only registered people can use the mailhelp command.\n");
+ return COM_OK;
+ }
+
+ if (param[0].type == TYPE_NULL) {
+ p1 = p;
+ } else if (param[0].type == TYPE_WORD) {
+ p1 = player_find_part_login(param[0].val.word);
+ if (p1 < 0) {
+ pprintf(p, "No user named \"%s\" is logged in.\n", param[0].val.word);
+ return COM_OK;
+ }
+ }
+ g = FindOldGameFor(p1);
+ if (g < 0) {
+ pprintf(p, "There is no old game for %s.\n", parray[p1].name);
+ return COM_OK;
+ }
+ if ((garray[g].white != p) && (garray[g].black != p) && (garray[g].private) && (parray[p].adminLevel < ADMIN_ADMIN)) {
+ pprintf(p, "Sorry, that is a private game.\n");
+ return COM_OK;
+ }
+ sprintf(subj, "FICS game report %s vs %s", garray[g].white_name, garray[g].black_name);
+ if (mail_string_to_user(p, subj, movesToString(g, parray[p].pgn))) {
+ pprintf(p, "Moves NOT mailed, perhaps your address is incorrect.\n");
+ } else {
+ pprintf(p, "Moves mailed.\n");
+ }
+ return COM_OK;
+}
+
+PUBLIC int com_load(int p, param_list param)
+{
+ pprintf(p, "Obsolete command, please use match <opponent>.\n");
+ return COM_OK;
+}
+
+void ExamineScratch(int p)
+{
+ char category, board;
+ int g = game_new();
+
+ unobserveAll(p);
+
+ player_decline_offers(p, -1, PEND_MATCH);
+ player_withdraw_offers(p, -1, PEND_MATCH);
+ player_withdraw_offers(p, -1, PEND_SIMUL);
+
+ garray[g].wInitTime = garray[g].wIncrement = 0;
+ garray[g].bInitTime = garray[g].bIncrement = 0;
+ garray[g].timeOfStart = tenth_secs();
+ garray[g].wTime = garray[g].bTime = 0;
+ garray[g].rated = 0;
+ garray[g].clockStopped = 0;
+ garray[g].type = TYPE_UNTIMED;
+ garray[g].white = garray[g].black = p;
+ garray[g].status = GAME_EXAMINE;
+ garray[g].startTime = tenth_secs();
+ garray[g].lastMoveTime = garray[g].startTime;
+ garray[g].lastDecTime = garray[g].startTime;
+ garray[g].totalHalfMoves = 0;
+
+ parray[p].side = WHITE; /* oh well... */
+ parray[p].game = g;
+
+ category = board = '\0';
+ if (board_init(&garray[g].game_state, &category, &board)) {
+ pprintf(p, "PROBLEM LOADING BOARD. Game Aborted.\n");
+ fprintf(stderr, "FICS: PROBLEM LOADING BOARD. Game Aborted.\n");
+ }
+ garray[g].game_state.gameNum = g;
+ strcpy(garray[g].white_name, parray[p].name);
+ strcpy(garray[g].black_name, parray[p].name);
+
+ send_boards(g);
+
+ strcpy(garray[g].boardList[garray[g].numHalfMoves], boardToFEN(g));
+}
+
+PRIVATE int ExamineStored(FILE * fp, int p, char *filename)
+{
+ int g;
+ char category[100], board[100];
+ game *gg;
+
+ unobserveAll(p);
+
+ player_decline_offers(p, -1, PEND_MATCH);
+ player_withdraw_offers(p, -1, PEND_MATCH);
+ player_withdraw_offers(p, -1, PEND_SIMUL);
+
+ g = game_new();
+ gg = &garray[g];
+ category[0] = '\0';
+ board[0] = '\0';
+ if (board_init(&gg->game_state, category, board)) {
+ pprintf(p, "PROBLEM LOADING BOARD. Game Aborted.\n");
+ fprintf(stderr, "FICS: PROBLEM LOADING BOARD %s %s. Game Aborted.\n",
+ category, board);
+ return -1;
+ }
+ gg->status = GAME_EXAMINE;
+ if (ReadGameAttrs(fp, filename, g) < 0) {
+ pprintf(p, "Gamefile is corrupt; please notify an admin.\n");
+ return -1;
+ }
+ gg->totalHalfMoves = gg->numHalfMoves;
+ gg->numHalfMoves = 0;
+ gg->revertHalfMove = 0;
+ gg->white = p;
+ gg->black = p;
+ gg->game_state.gameNum = g;
+
+ gg->startTime = tenth_secs();
+ gg->lastMoveTime = gg->startTime;
+ gg->lastDecTime = gg->startTime;
+
+ parray[p].side = WHITE; /* oh well... */
+ parray[p].game = g;
+
+ send_boards(g);
+
+ strcpy(gg->boardList[gg->numHalfMoves], boardToFEN(g));
+ return g;
+}
+
+void ExamineAdjourned(int p, int p1, int p2)
+{
+ FILE *fp;
+ char filename[1024];
+ char *p1Login, *p2Login;
+ int g;
+
+ p1Login = parray[p1].login;
+ p2Login = parray[p2].login;
+
+ sprintf(filename, "%s/%c/%s-%s", adj_dir, *p1Login, p1Login, p2Login);
+ fp = fopen(filename, "r");
+ if (!fp) {
+ sprintf(filename, "%s/%c/%s-%s", adj_dir, *p2Login, p1Login, p2Login);
+ fp = fopen(filename, "r");
+ if (!fp) {
+ sprintf(filename, "%s/%c/%s-%s", adj_dir, *p2Login, p2Login, p1Login);
+ fp = fopen(filename, "r");
+ if (!fp) {
+ sprintf(filename, "%s/%c/%s-%s", adj_dir, *p1Login, p2Login, p1Login);
+ fp = fopen(filename, "r");
+ if (!fp) {
+ pprintf(p, "No stored game between \"%s\" and \"%s\".\n",
+ parray[p1].name, parray[p2].name);
+ return;
+ }
+ }
+ }
+ }
+ g = ExamineStored(fp, p, filename);
+ fclose(fp);
+
+ if (g >= 0) {
+ if (garray[g].white_name[0] == '\0')
+ strcpy(garray[g].white_name, p1Login);
+ if (garray[g].black_name[0] == '\0')
+ strcpy(garray[g].black_name, p2Login);
+ }
+ return;
+}
+
+char *FindHistory(int p, int p1, int game)
+{
+ FILE *fpHist;
+ static char fileName[MAX_FILENAME_SIZE];
+ int index;
+ long when;
+
+ sprintf(fileName, "%s/player_data/%c/%s.%s", stats_dir,
+ parray[p1].login[0], parray[p1].login, STATS_GAMES);
+ fpHist = fopen(fileName, "r");
+ if (fpHist == NULL) {
+ pprintf(p, "No games in history for %s.\n", parray[p1].name);
+ return(NULL);
+ }
+ do {
+ fscanf(fpHist, "%d %*c %*d %*c %*d %*s %*s %*d %*d %*d %*d %*s %*s %ld",
+ &index, &when);
+ } while (!feof(fpHist) && index != game);
+
+ if (feof(fpHist)) {
+ pprintf(p, "There is no history game %d for %s.\n", game, parray[p1].name);
+ fclose(fpHist);
+ return(NULL);
+ }
+ fclose(fpHist);
+
+ sprintf(fileName, "%s/%ld/%ld", hist_dir, when % 100, when);
+ return(fileName);
+}
+
+void ExamineHistory(int p, int p1, int game)
+{
+ char *fileName;
+
+ fileName = FindHistory(p, p1, game);
+ if (fileName != NULL) {
+ FILE *fpGame = fopen(fileName, "r");
+ if (fpGame == NULL) {
+ pprintf(p, "History game %d not available for %s.\n", game, parray[p1].name);
+ } else {
+ ExamineStored(fpGame, p, fileName);
+ }
+ }
+ return;
+}
+
+PUBLIC int com_examine(int p, param_list param)
+{
+ int p1, p2 = p, p1conn, p2conn = 1;
+
+ if ((parray[p].game >=0) &&(garray[parray[p].game].status == GAME_EXAMINE)) {
+ pprintf(p, "You are already examining a game.\n");
+ } else if (parray[p].game >=0) {
+ pprintf(p, "You are playing a game.\n");
+ } else if (param[0].type == TYPE_NULL) {
+ ExamineScratch(p);
+ } else if (param[0].type == TYPE_WORD) {
+ if (!FindPlayer(p, &param[0], &p1, &p1conn))
+ return COM_OK;
+
+ if (param[1].type == TYPE_INT)
+ ExamineHistory(p, p1, param[1].val.integer);
+ else {
+ if (param[1].type == TYPE_WORD
+ && !FindPlayer(p, &param[1], &p2, &p2conn))
+ return COM_OK;
+
+ ExamineAdjourned(p, p1, p2);
+ if (!p2conn)
+ player_remove(p2);
+ }
+ if (!p1conn)
+ player_remove(p1);
+ }
+ return COM_OK;
+}
+
+PUBLIC int com_stored(int p, param_list param)
+{
+ DIR *dirp;
+#ifdef USE_DIRENT
+ struct dirent *dp;
+#else
+ struct direct *dp;
+#endif
+ int p1, connected;
+ char dname[MAX_FILENAME_SIZE];
+#if 0 /* replacing all the code below with a
+ FindPlayer call; This stuff was buggy
+ anyway. */
+ if (param[0].type == TYPE_WORD) {
+ if ((p1 = player_find_part_login(param[0].val.word)) < 0) { /* not logged in */
+ connected = 0;
+ p1 = player_new();
+ if (player_read(p1, param[0].val.word)) {
+ player_remove(p1);
+ pprintf(p, "There is no player by that name.\n");
+ return COM_OK;
+ }
+ } else {
+ connected = 1;
+ }
+ } else {
+ p1 = p;
+ connected = 1;
+ }
+#endif
+ if (!FindPlayer(p, &param[0], &p1, &connected))
+ return COM_OK;
+
+ sprintf(dname, "%s/%c", adj_dir, parray[p1].login[0]);
+ dirp = opendir(dname);
+ if (!dirp) {
+ pprintf(p, "Player %s has no games stored.\n", parray[p1].name);
+ if (!connected)
+ player_remove(p1);
+ return COM_OK;
+ }
+ pprintf(p, "Stored games for %s:\n", parray[p1].name);
+ for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
+ if (file_has_pname(dp->d_name, parray[p1].login)) {
+ pprintf(p, " %s vs. %s\n", file_wplayer(dp->d_name), file_bplayer(dp->d_name));
+ }
+ }
+
+ closedir(dirp);
+ pprintf(p, "\n");
+ if (!connected)
+ player_remove(p1);
+ return COM_OK;
+}
+
+PUBLIC int com_mailstored(int p, param_list param)
+{
+ int wp, wconnected, bp, bconnected, gotit = 0;
+ int g = -1;
+
+ if (!FindPlayer(p, &param[0], &wp, &wconnected))
+ return (COM_OK);
+
+ if (param[1].type == TYPE_INT) { /* look for a game from history */
+ char *fileName = FindHistory(p, wp, param[1].val.integer);
+ if (fileName != NULL) {
+ FILE *fpGame = fopen(fileName, "r");
+ if (fpGame == NULL) {
+ pprintf(p, "History game %d not available for %s.\n", param[1].val.integer, parray[wp].name);
+ } else {
+ g = game_new();
+ if (ReadGameAttrs(fpGame, fileName, g) < 0)
+ pprintf(p, "Gamefile is corrupt; please notify an admin.\n");
+ else
+ gotit = 1;
+ }
+ fclose(fpGame);
+ }
+ } else { /* look for a stored game between the players */
+ if (FindPlayer(p, &param[1], &bp, &bconnected)) {
+
+ g = game_new();
+ if (game_read(g, wp, bp) >= 0) { /* look for a game white-black, */
+ gotit = 1;
+ } else if (game_read(g, bp, wp) >= 0) { /* or black-white */
+ gotit = 1;
+ } else {
+ pprintf(p, "There is no stored game %s vs. %s\n", parray[wp].name, parray[bp].name);
+ }
+ if (!bconnected)
+ player_remove(bp);
+ }
+ }
+
+ if (gotit) {
+ if (strcasecmp(parray[p].name, garray[g].white_name) && strcasecmp(parray[p]
+.name, garray[g].black_name) && garray[g].private && (parray[p].adminLevel < ADMIN_ADMIN)) {
+ pprintf(p, "Sorry, that is a private game.\n");
+ } else {
+ char subj[81];
+ if (param[1].type == TYPE_INT)
+ sprintf(subj, "FICS history game: %s %d", parray[wp].name, param[1].val.integer);
+ else
+ sprintf(subj, "FICS adjourned game %s vs %s", garray[g].white_name, garray[g].black_name);
+ if (mail_string_to_user(p, subj, movesToString(g, parray[p].pgn)))
+ pprintf(p, "Moves NOT mailed, perhaps your address is incorrect.\n");
+ else
+ pprintf(p, "Moves mailed.\n");
+ }
+ }
+ if (!wconnected)
+ player_remove(wp);
+ if (g != -1)
+ game_remove(g);
+ return(COM_OK);
+}
+
+/* it would be good to write a FindStored and nuke all the game_read(foo,bar)
+ game_read(bar,foo) etc. this stuff is a mess... */
+
+PUBLIC int com_smoves(int p, param_list param)
+{
+ int wp, wconnected, bp, bconnected, gotit = 0;
+ int g = -1;
+
+ if (!FindPlayer(p, &param[0], &wp, &wconnected))
+ return(COM_OK);
+
+ if (param[1].type == TYPE_INT) {
+/* look for a game from history */
+ char *fileName = FindHistory(p, wp, param[1].val.integer);
+ if (fileName != NULL) {
+ FILE *fpGame = fopen(fileName, "r");
+ if (fpGame == NULL) {
+ pprintf(p, "History game %d not available for %s.\n", param[1].val.integer, parray[wp].name);
+ } else {
+ g = game_new();
+ if (ReadGameAttrs(fpGame, fileName, g) < 0) {
+ pprintf(p, "Gamefile is corrupt; please notify an admin.\n");
+ } else {
+ gotit = 1;
+ }
+ }
+ fclose(fpGame);
+ }
+ } else {
+/* look for a stored game between the players */
+ if (FindPlayer(p, &param[1], &bp, &bconnected)) {
+
+ g = game_new();
+ if (game_read(g, wp, bp) >= 0) { /* look for a game white-black, */
+ gotit = 1;
+ } else if (game_read(g, bp, wp) >= 0) { /* or black-white */
+ gotit = 1;
+ } else {
+ pprintf(p, "There is no stored game %s vs. %s\n", parray[wp].name, parray[bp].name);
+ }
+ if (!bconnected)
+ player_remove(bp);
+ }
+ }
+
+ if (gotit) {
+ if (strcasecmp(parray[p].name, garray[g].white_name) && strcasecmp(parray[p].name, garray[g].black_name) && garray[g].private && (parray[p].adminLevel < ADMIN_ADMIN)) {
+ pprintf(p, "Sorry, that is a private game.\n");
+ } else {
+ pprintf(p, "%s\n", movesToString(g, 0));
+ }
+ }
+ if (!wconnected)
+ player_remove(wp);
+ if (g != -1)
+ game_remove(g);
+ return(COM_OK);
+}
+
+PUBLIC int com_sposition(int p, param_list param)
+{
+ int wp, wconnected, bp, bconnected, confused = 0;
+ int g;
+
+ if (!FindPlayer(p, &param[0], &wp, &wconnected))
+ return (COM_OK);
+ if (!FindPlayer(p, &param[1], &bp, &bconnected))
+ return COM_OK;
+
+ g = game_new();
+ if (game_read(g, wp, bp) < 0) { /* if no game white-black, */
+ if (game_read(g, bp, wp) < 0) { /* look for black-white */
+ confused = 1;
+ pprintf(p, "There is no stored game %s vs. %s\n", parray[wp].name, parray[bp].name);
+ } else {
+ int tmp;
+ tmp = wp;
+ wp = bp;
+ bp = tmp;
+ tmp = wconnected;
+ wconnected = bconnected;
+ bconnected = tmp;
+ }
+ }
+ if (!confused) {
+ if ((wp != p) && (bp != p) && (garray[g].private) && (parray[p].adminLevel < ADMIN_ADMIN)) {
+ pprintf(p, "Sorry, that is a private game.\n");
+ } else {
+ garray[g].white = wp;
+ garray[g].black = bp;
+ garray[g].startTime = tenth_secs();
+ garray[g].lastMoveTime = garray[g].startTime;
+ garray[g].lastDecTime = garray[g].startTime;
+ pprintf(p, "Position of stored game %s vs. %s\n", parray[wp].name, parray[bp].name);
+ send_board_to(g, p);
+ }
+ }
+ game_remove(g);
+ if (!wconnected)
+ player_remove(wp);
+ if (!bconnected)
+ player_remove(bp);
+ return COM_OK;
+}
+
+PUBLIC int com_forward(int p, param_list param)
+{
+ int nHalfMoves = 1;
+ int g, i;
+ int p1;
+ unsigned now;
+
+ if (!((parray[p].game >=0) &&(garray[parray[p].game].status == GAME_EXAMINE))) {
+ pprintf(p, "You are not examining any games.\n");
+ return COM_OK;
+ }
+ g = parray[p].game;
+ if (!strcmp(garray[g].white_name, garray[g].black_name)) {
+ pprintf(p, "You cannot go forward; no moves are stored.\n");
+ return COM_OK;
+ }
+ if (param[0].type == TYPE_INT) {
+ nHalfMoves = param[0].val.integer;
+ }
+ if (garray[g].numHalfMoves > garray[g].revertHalfMove) {
+ pprintf(p, "No more moves.\n");
+ return COM_OK;
+ }
+ if (garray[g].numHalfMoves < garray[g].totalHalfMoves) {
+ for (p1 = 0; p1 < p_num; p1++) {
+ if (parray[p1].status != PLAYER_PROMPT)
+ continue;
+ if (player_is_observe(p1, g) || parray[p1].game == g) {
+ pprintf(p1, "%s goes forward %d move%s.\n",
+ parray[p].name, nHalfMoves, (nHalfMoves == 1) ? "" : "s");
+ }
+ }
+ }
+ for (i = 0; i < nHalfMoves; i++) {
+ if (garray[g].numHalfMoves < garray[g].totalHalfMoves) {
+ execute_move(&garray[g].game_state, &garray[g].moveList[garray[g].numHalfMoves], 1);
+ if (garray[g].numHalfMoves + 1 > garray[g].examMoveListSize) {
+ garray[g].examMoveListSize += 20; /* Allocate 20 moves at a
+ time */
+ if (!garray[g].examMoveList) {
+ garray[g].examMoveList = (move_t *) rmalloc(sizeof(move_t) * garray[g].examMoveListSize);
+ } else {
+ garray[g].examMoveList = (move_t *) rrealloc(garray[g].examMoveList, sizeof(move_t) * garray[g].examMoveListSize);
+ }
+ }
+ garray[g].examMoveList[garray[g].numHalfMoves] = garray[g].moveList[garray[g].numHalfMoves];
+ garray[g].revertHalfMove++;
+ garray[g].numHalfMoves++;
+ } else {
+ for (p1 = 0; p1 < p_num; p1++) {
+ if (parray[p1].status != PLAYER_PROMPT)
+ continue;
+ if (player_is_observe(p1, g) || parray[p1].game == g) {
+ pprintf(p1, "End of game.\n");
+ }
+ }
+ break;
+ }
+ }
+ /* roll back time */
+ if (garray[g].game_state.onMove == WHITE) {
+ garray[g].wTime += (garray[g].lastDecTime - garray[g].lastMoveTime);
+ } else {
+ garray[g].bTime += (garray[g].lastDecTime - garray[g].lastMoveTime);
+ }
+ now = tenth_secs();
+ if (garray[g].numHalfMoves == 0)
+ garray[g].timeOfStart = now;
+ garray[g].lastMoveTime = now;
+ garray[g].lastDecTime = now;
+ send_boards(g);
+ return COM_OK;
+}
+
+PUBLIC int com_backward(int p, param_list param)
+{
+ int nHalfMoves = 1;
+ int g, i;
+ int p1;
+ unsigned now;
+
+ if (!((parray[p].game >=0) &&(garray[parray[p].game].status == GAME_EXAMINE))) {
+ pprintf(p, "You are not examining any games.\n");
+ return COM_OK;
+ }
+ g = parray[p].game;
+ if (param[0].type == TYPE_INT) {
+ nHalfMoves = param[0].val.integer;
+ }
+ if (garray[g].numHalfMoves != 0) {
+ for (p1 = 0; p1 < p_num; p1++) {
+ if (parray[p1].status != PLAYER_PROMPT)
+ continue;
+ if (player_is_observe(p1, g) || parray[p1].game == g) {
+ pprintf(p1, "%s backs up %d move%s.\n",
+ parray[p].name, nHalfMoves, (nHalfMoves == 1) ? "" : "s");
+ }
+ }
+ }
+ for (i = 0; i < nHalfMoves; i++) {
+ if (backup_move(g, REL_EXAMINE) != MOVE_OK) {
+ for (p1 = 0; p1 < p_num; p1++) {
+ if (parray[p1].status != PLAYER_PROMPT)
+ continue;
+ if (player_is_observe(p1, g) || parray[p1].game == g) {
+ pprintf(p1, "Beginning of game.\n");
+ }
+ }
+
+ break;
+ }
+ }
+ if (garray[g].numHalfMoves < garray[g].revertHalfMove) {
+ garray[g].revertHalfMove = garray[g].numHalfMoves;
+ }
+ /* roll back time */
+ if (garray[g].game_state.onMove == WHITE) {
+ garray[g].wTime += (garray[g].lastDecTime - garray[g].lastMoveTime);
+ } else {
+ garray[g].bTime += (garray[g].lastDecTime - garray[g].lastMoveTime);
+ }
+ now = tenth_secs();
+ if (garray[g].numHalfMoves == 0)
+ garray[g].timeOfStart = now;
+ garray[g].lastMoveTime = now;
+ garray[g].lastDecTime = now;
+ send_boards(g);
+ return COM_OK;
+}
+
+PUBLIC int com_revert(int p, param_list param)
+{
+ int nHalfMoves = 1;
+ int g, i;
+ int p1;
+ unsigned now;
+
+ if (!((parray[p].game >=0) &&(garray[parray[p].game].status == GAME_EXAMINE))) {
+ pprintf(p, "You are not examining any games.\n");
+ return COM_OK;
+ }
+ g = parray[p].game;
+ nHalfMoves = garray[g].numHalfMoves - garray[g].revertHalfMove;
+ if (nHalfMoves == 0) {
+ pprintf(p, "Already at mainline.\n");
+ return COM_OK;
+ }
+ if (nHalfMoves < 0) { /* eek - should NEVER happen! */
+ fprintf(stderr, "OUCH! in com_revert: nHalfMoves < 0\n");
+ return COM_OK;
+ }
+ for (p1 = 0; p1 < p_num; p1++) {
+ if (parray[p1].status != PLAYER_PROMPT)
+ continue;
+ if (player_is_observe(p1, g) || parray[p1].game == g) {
+ pprintf(p1, "%s reverts to mainline.\n", parray[p].name);
+ }
+ }
+ for (i = 0; i < nHalfMoves; i++) {
+ backup_move(g, REL_EXAMINE);/* should never return error */
+ }
+ /* roll back time */
+ if (garray[g].game_state.onMove == WHITE) {
+ garray[g].wTime += (garray[g].lastDecTime - garray[g].lastMoveTime);
+ } else {
+ garray[g].bTime += (garray[g].lastDecTime - garray[g].lastMoveTime);
+ }
+ now = tenth_secs();
+ if (garray[g].numHalfMoves == 0)
+ garray[g].timeOfStart = now;
+ garray[g].lastMoveTime = now;
+ garray[g].lastDecTime = now;
+ send_boards(g);
+ return COM_OK;
+}
+
+PUBLIC int com_takeback(int p, param_list param)
+{
+ int nHalfMoves = 1;
+ int from;
+ int g, i;
+ int p1;
+
+ if ((parray[p].game <0) ||(garray[parray[p].game].status == GAME_EXAMINE)) {
+ pprintf(p, "You are not playing a game.\n");
+ return COM_OK;
+ }
+ p1 = parray[p].opponent;
+ if (parray[p1].simul_info.numBoards &&
+ parray[p1].simul_info.boards[parray[p1].simul_info.onBoard] !=
+ parray[p].game) {
+ pprintf(p, "You can only make requests when the simul player is at your board.\n");
+ return COM_OK;
+ }
+ g = parray[p].game;
+ if (param[0].type == TYPE_INT) {
+ nHalfMoves = param[0].val.integer;
+ }
+ if ((from = player_find_pendfrom(p, parray[p].opponent, PEND_TAKEBACK)) >= 0) {
+ player_remove_request(parray[p].opponent, p, PEND_TAKEBACK);
+ if (parray[p].p_from_list[from].param1 == nHalfMoves) {
+ /* Doing the takeback */
+ player_decline_offers(p, -1, -PEND_SIMUL);
+ for (i = 0; i < nHalfMoves; i++) {
+ if (backup_move(g, REL_GAME) != MOVE_OK) {
+ pprintf(garray[g].white, "Can only backup %d moves\n", i);
+ pprintf(garray[g].black, "Can only backup %d moves\n", i);
+ break;
+ }
+ }
+
+#ifdef TIMESEAL
+
+ garray[g].wTimeWhenReceivedMove = 0;
+ garray[g].bTimeWhenReceivedMove = 0;
+
+#endif
+
+ send_boards(g);
+ } else {
+ if (garray[g].numHalfMoves < nHalfMoves) {
+ pprintf(p, "There are only %d half moves in your game.\n", garray[g].numHalfMoves);
+ pprintf_prompt(parray[p].opponent, "\n%s has declined the takeback request.\n", parray[p].name, nHalfMoves);
+ return COM_OK;
+ }
+ pprintf(p, "You disagree on the number of half-moves to takeback.\n");
+ pprintf(p, "Alternate takeback request sent.\n");
+ pprintf_prompt(parray[p].opponent, "\n%s proposes a different number (%d) of half-move(s).\n", parray[p].name, nHalfMoves);
+ player_add_request(p, parray[p].opponent, PEND_TAKEBACK, nHalfMoves);
+ }
+ } else {
+ if (garray[g].numHalfMoves < nHalfMoves) {
+ pprintf(p, "There are only %d half moves in your game.\n", garray[g].numHalfMoves);
+ return COM_OK;
+ }
+ pprintf(parray[p].opponent, "\n");
+ pprintf_highlight(parray[p].opponent, "%s", parray[p].name);
+ pprintf_prompt(parray[p].opponent, " would like to take back %d half move(s).\n",
+ nHalfMoves);
+ pprintf(p, "Takeback request sent.\n");
+ player_add_request(p, parray[p].opponent, PEND_TAKEBACK, nHalfMoves);
+ }
+ return COM_OK;
+}
+
+
+PUBLIC int com_switch(int p, param_list param)
+{
+ int g = parray[p].game;
+ int tmp, now;
+ int p1;
+ char *strTmp;
+
+ if ((g < 0) || (garray[g].status == GAME_EXAMINE)) {
+ pprintf(p, "You are not playing a game.\n");
+ return COM_OK;
+ }
+ p1 = parray[p].opponent;
+ if (parray[p1].simul_info.numBoards &&
+ parray[p1].simul_info.boards[parray[p1].simul_info.onBoard] != g) {
+ pprintf(p, "You can only make requests when the simul player is at your board.\n");
+ return COM_OK;
+ }
+ if (player_find_pendfrom(p, parray[p].opponent, PEND_SWITCH) >= 0) {
+ player_remove_request(parray[p].opponent, p, PEND_SWITCH);
+ /* Doing the switch */
+ player_decline_offers(p, -1, -PEND_SIMUL);
+
+ tmp = garray[g].white;
+ garray[g].white = garray[g].black;
+ garray[g].black = tmp;
+ parray[p].side = (parray[p].side == WHITE) ? BLACK : WHITE;
+ strTmp = strdup(garray[g].white_name);
+ strcpy(garray[g].white_name, garray[g].black_name);
+ strcpy(garray[g].black_name, strTmp);
+ strfree(strTmp);
+
+ parray[parray[p].opponent].side =
+ (parray[parray[p].opponent].side == WHITE) ? BLACK : WHITE;
+ /* Roll back the time */
+ if (garray[g].game_state.onMove == WHITE) {
+ garray[g].wTime += (garray[g].lastDecTime - garray[g].lastMoveTime);
+ } else {
+ garray[g].bTime += (garray[g].lastDecTime - garray[g].lastMoveTime);
+ }
+ now = tenth_secs();
+ if (garray[g].numHalfMoves == 0)
+ garray[g].timeOfStart = now;
+ garray[g].lastMoveTime = now;
+ garray[g].lastDecTime = now;
+ send_boards(g);
+ return COM_OK;
+ }
+ if (garray[g].rated && garray[g].numHalfMoves > 0) {
+ pprintf(p, "You cannot switch sides once a rated game is underway.\n");
+ return COM_OK;
+ }
+ pprintf(parray[p].opponent, "\n");
+ pprintf_highlight(parray[p].opponent, "%s", parray[p].name);
+ pprintf_prompt(parray[p].opponent, " would like to switch sides.\nType \"accept\" to switch sides, or \"decline\" to refuse.\n");
+ pprintf(p, "Switch request sent.\n");
+ player_add_request(p, parray[p].opponent, PEND_SWITCH, 0);
+ return COM_OK;
+}
+
+
+PUBLIC int com_history(int p, param_list param)
+{
+ int p1, connected;
+ char fname[MAX_FILENAME_SIZE];
+
+ if (!FindPlayer(p, &param[0], &p1, &connected))
+ return COM_OK;
+
+ sprintf(fname, "%s/player_data/%c/%s.%s", stats_dir, parray[p1].login[0],
+ parray[p1].login, STATS_GAMES);
+ pgames(p, p1, fname);
+ if (!connected)
+ player_remove(p1);
+ return COM_OK;
+}
+
+PUBLIC int com_time(int p, param_list param)
+{
+ int p1, g;
+
+ if (param[0].type == TYPE_NULL) {
+ g = parray[p].game;
+ if ((g < 0) || (garray[g].status == GAME_EXAMINE)) {
+ pprintf(p, "You are not playing a game.\n");
+ return COM_OK;
+ }
+ } else {
+ g = GameNumFromParam(p, &p1, &param[0]);
+ if (g < 0)
+ return COM_OK;
+ }
+ if ((g < 0) || (g >= g_num) || (garray[g].status != GAME_ACTIVE)) {
+ pprintf(p, "There is no such game.\n");
+ return COM_OK;
+ }
+ game_update_time(g);
+ pprintf(p, "White (%s) : %d mins, %d secs\n",
+ parray[garray[g].white].name,
+ garray[g].wTime / 600,
+ (garray[g].wTime - ((garray[g].wTime / 600) * 600)) / 10);
+ pprintf(p, "Black (%s) : %d mins, %d secs\n",
+ parray[garray[g].black].name,
+ garray[g].bTime / 600,
+ (garray[g].bTime - ((garray[g].bTime / 600) * 600)) / 10);
+ return COM_OK;
+}
+
+PUBLIC int com_boards(int p, param_list param)
+{
+ char *category = NULL;
+ char dname[MAX_FILENAME_SIZE];
+ DIR *dirp;
+#ifdef USE_DIRENT
+ struct dirent *dp;
+#else
+ struct direct *dp;
+#endif
+
+ if (param[0].type == TYPE_WORD)
+ category = param[0].val.word;
+ if (category) {
+ pprintf(p, "Boards Available For Category %s:\n", category);
+ sprintf(dname, "%s/%s", board_dir, category);
+ } else {
+ pprintf(p, "Categories Available:\n");
+ sprintf(dname, "%s", board_dir);
+ }
+ dirp = opendir(dname);
+ if (!dirp) {
+ pprintf(p, "No such category %s, try \"boards\".\n", category);
+ return COM_OK;
+ }
+ for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
+ if (!strcmp(dp->d_name, "."))
+ continue;
+ if (!strcmp(dp->d_name, ".."))
+ continue;
+ pprintf(p, "%s\n", dp->d_name);
+ }
+ closedir(dirp);
+ return COM_OK;
+}
+
+PUBLIC int com_simmatch(int p, param_list param)
+{
+ int p1, g, adjourned;
+ int num;
+ char tmp[100];
+
+ if ((parray[p].game >=0) &&(garray[parray[p].game].status == GAME_EXAMINE)) {
+ pprintf(p, "You are still examining a game.\n");
+ return COM_OK;
+ }
+ p1 = player_find_part_login(param[0].val.word);
+ if (p1 < 0) {
+ pprintf(p, "No user named \"%s\" is logged in.\n", param[0].val.word);
+ return COM_OK;
+ }
+ if (p == p1) {
+ pprintf(p, "You can't simmatch yourself!\n");
+ return COM_OK;
+ }
+ if (player_find_pendfrom(p, p1, PEND_SIMUL) >= 0) {
+ player_remove_request(p, p1, PEND_MATCH);
+ player_remove_request(p1, p, PEND_MATCH);
+ player_remove_request(p, p1, PEND_SIMUL);
+ player_remove_request(p1, p, PEND_SIMUL);
+ player_withdraw_offers(p, -1, PEND_SIMUL);
+ player_decline_offers(p1, -1, PEND_SIMUL);
+ player_withdraw_offers(p1, -1, PEND_SIMUL);
+ player_decline_offers(p, -1, PEND_MATCH);
+ player_withdraw_offers(p, -1, PEND_MATCH);
+ player_decline_offers(p1, -1, PEND_MATCH);
+ player_withdraw_offers(p1, -1, PEND_MATCH);
+
+
+
+ /* Accepting Simul ! */
+
+
+ if (parray[p].simul_info.numBoards >= MAX_SIMUL) {
+ pprintf(p, "You are already playing the maximum of %d boards.\n", MAX_SIMUL);
+ pprintf(p1, "Simul request removed, boards filled.\n");
+ return COM_OK;
+ }
+ unobserveAll(p); /* stop observing when match starts */
+ unobserveAll(p1);
+
+ g = game_new();
+ adjourned = 0;
+ if (game_read(g, p, p1) >= 0)
+ adjourned = 1;
+ if (!adjourned) { /* no adjourned game, so begin a new game */
+ game_remove(g);
+
+ if (create_new_match(p, p1, 0, 0, 0, 0, 0, "standard", "standard", 1)) {
+ pprintf(p, "There was a problem creating the new match.\n");
+ pprintf_prompt(p1, "There was a problem creating the new match.\n");
+ return COM_OK;
+ }
+ } else { /* resume adjourned game */
+ game_delete(p, p1);
+
+ sprintf(tmp, "{Game %d (%s vs. %s) Continuing %s %s simul.}\n", g + 1, parray[p].name, parray[p1].name, rstr[garray[g].rated], bstr[garray[g].type]);
+ pprintf(p, tmp);
+ pprintf(p1, tmp);
+
+ garray[g].white = p;
+ garray[g].black = p1;
+ garray[g].status = GAME_ACTIVE;
+ garray[g].startTime = tenth_secs();
+ garray[g].lastMoveTime = garray[g].startTime;
+ garray[g].lastDecTime = garray[g].startTime;
+ parray[p].game = g;
+ parray[p].opponent = p1;
+ parray[p].side = WHITE;
+ parray[p1].game = g;
+ parray[p1].opponent = p;
+ parray[p1].side = BLACK;
+ send_boards(g);
+ }
+
+ num = parray[p].simul_info.numBoards;
+ parray[p].simul_info.results[num] = -1;
+ parray[p].simul_info.boards[num] = parray[p].game;
+ parray[p].simul_info.numBoards++;
+ if (parray[p].simul_info.numBoards > 1 &&
+ parray[p].simul_info.onBoard >= 0)
+ player_goto_board(p, parray[p].simul_info.onBoard);
+ else
+ parray[p].simul_info.onBoard = 0;
+ return COM_OK;
+ }
+ if (player_find_pendfrom(p, -1, PEND_SIMUL) >= 0) {
+ 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");
+ return COM_OK;
+ }
+ if (parray[p].simul_info.numBoards) {
+ 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");
+ return COM_OK;
+ }
+ if (parray[p].game >=0) {
+ pprintf(p, "You are already playing a game.\n");
+ return COM_OK;
+ }
+ if (!parray[p1].sopen) {
+ pprintf_highlight(p, "%s", parray[p1].name);
+ pprintf(p, " is not open to receiving simul requests.\n");
+ return COM_OK;
+ }
+ if (parray[p1].simul_info.numBoards >= MAX_SIMUL) {
+ pprintf_highlight(p, "%s", parray[p1].name);
+ pprintf(p, " is already playing the maximum of %d boards.\n", MAX_SIMUL);
+ return COM_OK;
+ }
+/* loon: checking for some crazy situations we can't allow :) */
+
+ if ((parray[p1].game >=0) &&(parray[p1].simul_info.numBoards == 0)) {
+ pprintf_highlight(p, "%s", parray[p1].name);
+ if (parray[garray[parray[p1].game].white].simul_info.numBoards) {
+ pprintf(p, " is playing in ");
+ pprintf_highlight(p, "%s", parray[parray[p1].opponent].name);
+ pprintf(p, "'s simul, and can't accept.\n");
+ } else {
+ pprintf(p, " can't begin a simul while playing a non-simul game.\n");
+ }
+ return COM_OK;
+ }
+/* loon: this was (p, p1, PEND_SIMUL) but player_add_request needs 4 args...
+if 0 is the incorrect 4th arg, please fix :) */
+
+ g = game_new(); /* Check if an adjourned untimed game */
+ adjourned = ((game_read(g, p, p1) < 0) && (game_read(g, p1, p) < 0)) ? 0 : 1;
+ if (adjourned) {
+ if (!(garray[g].type == TYPE_UNTIMED))
+ adjourned = 0;
+ }
+ game_remove(g);
+
+ if (player_add_request(p, p1, PEND_SIMUL, 0)) {
+ pprintf(p, "Maximum number of pending actions reached. Your request was not sent.\nTry again later.\n");
+ return COM_OK;
+ } else {
+ pprintf(p1, "\n");
+ pprintf_highlight(p1, "%s", parray[p].name);
+ if (adjourned) {
+ pprintf_prompt(p1, " requests to continue an adjourned simul game.\n");
+ pprintf(p, "Request to resume simul sent. Adjourned game found.\n");
+ } else {
+ pprintf_prompt(p1, " requests to join a simul match with you.\n");
+ pprintf(p, "Simul match request sent.\n");
+ }
+ }
+ return COM_OK;
+}
+
+PUBLIC int com_goboard(int p, param_list param)
+{
+ int on, g, p1;
+
+ if (!parray[p].simul_info.numBoards) {
+ pprintf(p, "You are not giving a simul.\n");
+ return COM_OK;
+ }
+ p1 = player_find_part_login(param[0].val.word);
+ if (p1 < 0) {
+ pprintf(p, "No user named \"%s\" is logged in.\n", param[0].val.word);
+ return COM_OK;
+ }
+ if (p == p1) {
+ pprintf(p, "You can't goboard yourself!\n");
+ return COM_OK;
+ }
+ on = parray[p].simul_info.onBoard;
+ g = parray[p].simul_info.boards[on];
+ if (p1 == garray[g].black) {
+ pprintf(p, "You are already at that board!\n");
+ return COM_OK;
+ }
+ if (parray[p].simul_info.numBoards > 1) {
+ player_decline_offers(p, -1, -PEND_SIMUL);
+ if (player_goto_simulgame_bynum(p, parray[p1].game) !=-1) {
+ if (g >= 0) {
+ pprintf(garray[g].black, "\n");
+ pprintf_highlight(garray[g].black, "%s", parray[p].name);
+ pprintf_prompt(garray[g].black, " has moved away from your board.\n");
+ }
+ }
+ } else
+ pprintf(p, "You are only playing one board!\n");
+ return COM_OK;
+}
+
+PUBLIC int com_gonum(int p, param_list param)
+{
+ int on, g, gamenum;
+
+ if (!parray[p].simul_info.numBoards) {
+ pprintf(p, "You are not giving a simul.\n");
+ return COM_OK;
+ }
+ on = parray[p].simul_info.onBoard;
+ g = parray[p].simul_info.boards[on];
+ gamenum = param[0].val.integer - 1;
+ if (gamenum < 0)
+ gamenum = 0;
+ if (on == gamenum) {
+ pprintf(p, "You are already at that board!\n");
+ return COM_OK;
+ }
+ if (parray[p].simul_info.numBoards > 1) {
+ player_decline_offers(p, -1, -PEND_SIMUL);
+ if (player_goto_simulgame_bynum(p, gamenum) != -1) {
+ if (g >= 0) {
+ pprintf(garray[g].black, "\n");
+ pprintf_highlight(garray[g].black, "%s", parray[p].name);
+ pprintf_prompt(garray[g].black, " has moved away from your board.\n");
+ }
+ }
+ } else
+ pprintf(p, "You are only playing one board!\n");
+ return COM_OK;
+}
+
+PUBLIC int com_simnext(int p, param_list param)
+{
+ int on, g;
+
+ if (!parray[p].simul_info.numBoards) {
+ pprintf(p, "You are not giving a simul.\n");
+ return COM_OK;
+ }
+ if (parray[p].simul_info.numBoards > 1) {
+ player_decline_offers(p, -1, -PEND_SIMUL);
+ on = parray[p].simul_info.onBoard;
+ g = parray[p].simul_info.boards[on];
+ if (g >= 0) {
+ pprintf(garray[g].black, "\n");
+ pprintf_highlight(garray[g].black, "%s", parray[p].name);
+ pprintf_prompt(garray[g].black, " is moving away from your board.\n");
+ player_goto_next_board(p);
+ }
+ } else
+ pprintf(p, "You are only playing one board!\n");
+ return COM_OK;
+}
+
+
+PUBLIC int com_simprev(int p, param_list param)
+{
+ int on, g;
+
+ if (!parray[p].simul_info.numBoards) {
+ pprintf(p, "You are not giving a simul.\n");
+ return COM_OK;
+ }
+ if (parray[p].simul_info.numBoards > 1) {
+ player_decline_offers(p, -1, -PEND_SIMUL);
+ on = parray[p].simul_info.onBoard;
+ g = parray[p].simul_info.boards[on];
+ if (g >= 0) {
+ pprintf(garray[g].black, "\n");
+ pprintf_highlight(garray[g].black, "%s", parray[p].name);
+ pprintf_prompt(garray[g].black, " is moving back to the previous board.\n");
+ }
+ player_goto_prev_board(p);
+ } else
+ pprintf(p, "You are only playing one board!\n");
+ return COM_OK;
+}
+
+PUBLIC int com_simgames(int p, param_list param)
+{
+ int p1 = p;
+
+ if (param[0].type == TYPE_WORD) {
+ if ((p1 = player_find_part_login(param[0].val.word)) < 0) {
+ pprintf(p, "No player named %s is logged in.\n", param[0].val.word);
+ return COM_OK;
+ }
+ }
+ if (p1 == p)
+ pprintf(p, "You are playing %d simultaneous games.\n",
+ player_num_active_boards(p1));
+ else
+ pprintf(p, "%s is playing %d simultaneous games.\n", parray[p1].name,
+ player_num_active_boards(p1));
+ return COM_OK;
+}
+
+PUBLIC int com_simpass(int p, param_list param)
+{
+ int g, p1, on;
+
+ if (parray[p].game <0) {
+ pprintf(p, "You are not playing a game.\n");
+ return COM_OK;
+ }
+ g = parray[p].game;
+ p1 = garray[g].white;
+ if (!parray[p1].simul_info.numBoards) {
+ pprintf(p, "You are not participating in a simul.\n");
+ return COM_OK;
+ }
+ if (p == p1) {
+ pprintf(p, "You are the simul holder and cannot pass!\n");
+ return COM_OK;
+ }
+ if (player_num_active_boards(p1) == 1) {
+ pprintf(p, "This is the only game, so passing is futile.\n");
+ return COM_OK;
+ }
+ on = parray[p1].simul_info.onBoard;
+ if (on != g) {
+ pprintf(p, "You cannot pass until the simul holder arrives!\n");
+ return COM_OK;
+ }
+ if (garray[g].passes >= MAX_SIMPASS) {
+ if (parray[p].bell)
+ pprintf(p, "\a");
+ pprintf(p, "You have reached your maximum of %d passes.\n", MAX_SIMPASS);
+ pprintf(p, "Please move IMMEDIATELY!\n");
+ pprintf_highlight(p1, "%s", parray[p].name);
+ pprintf_prompt(p1, " tried to pass, but is out of passes.\n");
+ return COM_OK;
+ }
+ player_decline_offers(p, -1, -PEND_SIMUL);
+
+ garray[g].passes++;
+ pprintf(p, "You have passed and have %d passes left.\n",
+ (MAX_SIMPASS - garray[g].passes));
+ pprintf_highlight(p1, "%s", parray[p].name);
+ pprintf_prompt(p1, " has decided to pass and has %d passes left.\n",
+ (MAX_SIMPASS - garray[g].passes));
+ player_goto_next_board(p1);
+ return COM_OK;
+}
+
+PUBLIC int com_simabort(int p, param_list param)
+{
+ if (!parray[p].simul_info.numBoards) {
+ pprintf(p, "You are not giving a simul.\n");
+ return COM_OK;
+ }
+ player_decline_offers(p, -1, -PEND_SIMUL);
+ game_ended(parray[p].simul_info.boards[parray[p].simul_info.onBoard],
+ WHITE, END_ABORT);
+ return COM_OK;
+}
+
+PUBLIC int com_simallabort(int p, param_list param)
+{
+ int i;
+
+ if (!parray[p].simul_info.numBoards) {
+ pprintf(p, "You are not giving a simul.\n");
+ return COM_OK;
+ }
+ player_decline_offers(p, -1, -PEND_SIMUL);
+ for (i = 0; i < parray[p].simul_info.numBoards; i++) {
+ if (parray[p].simul_info.boards[i] >= 0) {
+ game_ended(parray[p].simul_info.boards[i],
+ WHITE, END_ABORT);
+ }
+ }
+ return COM_OK;
+}
+
+PUBLIC int com_simadjourn(int p, param_list param)
+{
+ if (!parray[p].simul_info.numBoards) {
+ pprintf(p, "You are not giving a simul.\n");
+ return COM_OK;
+ }
+ player_decline_offers(p, -1, -PEND_SIMUL);
+ game_ended(parray[p].simul_info.boards[parray[p].simul_info.onBoard],
+ WHITE, END_ADJOURN);
+ return COM_OK;
+}
+
+PUBLIC int com_simalladjourn(int p, param_list param)
+{
+ int i;
+
+ if (!parray[p].simul_info.numBoards) {
+ pprintf(p, "You are not giving a simul.\n");
+ return COM_OK;
+ }
+ player_decline_offers(p, -1, -PEND_SIMUL);
+ for (i = 0; i < parray[p].simul_info.numBoards; i++) {
+ if (parray[p].simul_info.boards[i] >= 0) {
+ game_ended(parray[p].simul_info.boards[i],
+ WHITE, END_ADJOURN);
+ }
+ }
+ return COM_OK;
+}
+
+PUBLIC int com_moretime(int p, param_list param)
+{
+ int g, increment;
+
+ ASSERT(param[0].type == TYPE_INT);
+ if ((parray[p].game >=0) &&(garray[parray[p].game].status == GAME_EXAMINE)) {
+ pprintf(p, "You cannot use moretime in an examined game.\n");
+ return COM_OK;
+ }
+ increment = param[0].val.integer;
+ if (increment <= 0) {
+ pprintf(p, "Moretime requires an integer value greater than zero.\n");
+ return COM_OK;
+ }
+ if (parray[p].game <0) {
+ pprintf(p, "You are not playing a game.\n");
+ return COM_OK;
+ }
+ if (increment > 600) {
+ pprintf(p, "Moretime has a maximum limit of 600 seconds.\n");
+ increment = 600;
+ }
+ g = parray[p].game;
+ if (garray[g].white == p) {
+ garray[g].bTime += increment * 10;
+#ifdef TIMESEAL
+ garray[g].bRealTime += increment * 10 * 100;
+#endif
+ pprintf(p, "%d seconds were added to your opponents clock\n",
+ increment);
+ pprintf_prompt(parray[p].opponent,
+ "\nYour opponent has added %d seconds to your clock.\n",
+ increment);
+ }
+ if (garray[g].black == p) {
+ garray[g].wTime += increment * 10;;
+#ifdef TIMESEAL
+ garray[g].wRealTime += increment * 10 * 100;
+#endif
+ pprintf(p, "%d seconds were added to your opponents clock\n",
+ increment);
+ pprintf_prompt(parray[p].opponent,
+ "\nYour opponent has added %d seconds to your clock.\n",
+ increment);
+ }
+ return COM_OK;
+}