7e2cd5d8d2d160c4e029f553325e6cec8db66d18
[capablanca.git] / lasker-2.2.3 / src / gameproc.c
1 /*
2    Copyright (c) 1993 Richard V. Nash.
3    Copyright (c) 2000 Dan Papasian
4    Copyright (C) Andrew Tridgell 2002
5    
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.
10    
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.
15    
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.
19 */
20
21 #include "includes.h"
22
23 /*Let users know that someone is available (format the message)*/
24 static void getavailmess(int p, char* message)
25 {
26         struct player *pp = &player_globals.parray[p];
27         char titles[100];
28
29         titles [0]='\0';
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.",
33                  pp->name, titles,
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));
39 }
40
41 void getnotavailmess(int p, char* message)
42 {
43         struct player *pp = &player_globals.parray[p];
44         char titles[100];
45
46         titles[0]='\0';
47         AddPlayerLists(p,titles);
48         sprintf (message,"%s%s is no longer available for matches.",
49                  pp->name, titles);
50 }
51
52 void announce_avail(int p)
53 {
54         struct player *pp = &player_globals.parray[p];
55         char avail[200];
56         int p1;
57         if ((pp->game < 0) && (CheckPFlag(p, PFLAG_OPEN))) {
58                 getavailmess (p,avail);
59                 
60                 for (p1 = 0; p1 < player_globals.p_num; p1++) {
61                         if (p == p1)
62                                 continue;
63                         if (player_globals.parray[p1].status != PLAYER_PROMPT)
64                                 continue;
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);
69                 }
70         }
71 }
72
73 void announce_notavail(int p)
74 {
75         struct player *pp = &player_globals.parray[p];
76         char avail[200];
77         int p1;
78         
79         getnotavailmess (p,avail);
80         
81         for (p1 = 0; p1 < player_globals.p_num; p1++) {
82                 if (p == p1)
83                         continue;
84                 if (player_globals.parray[p1].status != PLAYER_PROMPT)
85                         continue;
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);
90         }
91 }
92
93 void game_ended(int g, int winner, int why)
94 {
95   struct game *gg = &game_globals.garray[g];
96   char outstr[200];
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];
101   char tmp[200];
102   int p;
103   int gl = gg->link;
104   int rate_change = 0;
105   int isDraw = 0;
106   int whiteResult;
107   char winSymbol[10];
108   char EndSymbol[10];
109   char *NameOfWinner, *NameOfLoser;
110   int beingplayed = 0;          /* i.e. it wasn't loaded for adjudication */
111   int print_avail = 0;
112
113   avail_white[0] = '\0';
114   avail_black[0] = '\0';
115   avail_bugwhite[0] = '\0';
116   avail_bugblack[0] = '\0';
117
118   beingplayed = (player_globals.parray[gg->black].game == g);
119
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);
123   gg->result = why;
124   gg->winner = winner;
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;
130   } else {
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;
135   }
136   switch (why) {
137   case END_CHECKMATE:
138     sprintf(tmp, "%s checkmated} %s", NameOfLoser, winSymbol);
139     strcpy(EndSymbol, "Mat");
140     rate_change = 1;
141     break;
142   case END_RESIGN:
143     sprintf(tmp, "%s resigns} %s", NameOfLoser, winSymbol);
144     strcpy(EndSymbol, "Res");
145     rate_change = 1;
146     break;
147   case END_FLAG:
148     sprintf(tmp, "%s forfeits on time} %s", NameOfLoser, winSymbol);
149     strcpy(EndSymbol, "Fla");
150     rate_change = 1;
151     break;
152   case END_STALEMATE:
153     sprintf(tmp, "Game drawn by stalemate} 1/2-1/2");
154     isDraw = 1;
155     strcpy(EndSymbol, "Sta");
156     rate_change = 1;
157     whiteResult = RESULT_DRAW;
158     break;
159   case END_AGREEDDRAW:
160     sprintf(tmp, "Game drawn by mutual agreement} 1/2-1/2");
161     isDraw = 1;
162     strcpy(EndSymbol, "Agr");
163     rate_change = 1;
164     whiteResult = RESULT_DRAW;
165     break;
166   case END_BOTHFLAG:
167     sprintf(tmp, "Game drawn because both players ran out of time} 1/2-1/2");
168     isDraw = 1;
169     strcpy(EndSymbol, "Fla");
170     rate_change = 1;
171     whiteResult = RESULT_DRAW;
172     break;
173   case END_REPETITION:
174     sprintf(tmp, "Game drawn by repetition} 1/2-1/2");
175     isDraw = 1;
176     strcpy(EndSymbol, "Rep");
177     rate_change = 1;
178     whiteResult = RESULT_DRAW;
179     break;
180   case END_50MOVERULE:
181     sprintf(tmp, "Game drawn by the 50 move rule} 1/2-1/2");
182     isDraw = 1;
183     strcpy(EndSymbol, "50");
184     rate_change = 1;
185     whiteResult = RESULT_DRAW;
186     break;
187   case END_ADJOURN:
188     if (gl >= 0) {
189       sprintf(tmp, "Bughouse game aborted.} *");
190       whiteResult = RESULT_ABORT;
191     } else {
192     sprintf(tmp, "Game adjourned by mutual agreement} *");
193     game_save(g);
194     }
195     break;
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)
200         && gl < 0) {
201       sprintf(tmp, "adjourned} *");
202       game_save(g);
203     } else
204       sprintf(tmp, "aborted} *");
205     whiteResult = RESULT_ABORT;
206     break;
207   case END_ABORT:
208     sprintf(tmp, "Game aborted by mutual agreement} *");
209     whiteResult = RESULT_ABORT;
210     break;
211   case END_COURTESY:
212     sprintf(tmp, "Game courtesyaborted by %s} *", NameOfWinner);
213     whiteResult = RESULT_ABORT;
214     break;
215   case END_COURTESYADJOURN:
216     if (gl >= 0) {
217       sprintf(tmp, "Bughouse game courtesyaborted by %s.} *", NameOfWinner);
218       whiteResult = RESULT_ABORT;
219     } else {
220     sprintf(tmp, "Game courtesyadjourned by %s} *", NameOfWinner);
221     game_save(g);
222     }
223     break;
224   case END_NOMATERIAL:
225     /* Draw by insufficient material (e.g., lone K vs. lone K) */
226     sprintf(tmp, "Neither player has mating material} 1/2-1/2");
227     isDraw = 1;
228     strcpy(EndSymbol, "NM ");
229     rate_change = 1;
230     whiteResult = RESULT_DRAW;
231     break;
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);
235     isDraw = 1;
236     strcpy(EndSymbol, "TM ");
237     rate_change = 1;
238     whiteResult = RESULT_DRAW;
239     break;
240   case END_ADJWIN:
241     sprintf(tmp, "%s wins by adjudication} %s", NameOfWinner, winSymbol);
242     strcpy(EndSymbol, "Adj");
243     rate_change = 1;
244     break;
245   case END_ADJDRAW:
246     sprintf(tmp, "Game drawn by adjudication} 1/2-1/2");
247     isDraw = 1;
248     strcpy(EndSymbol, "Adj");
249     rate_change = 1;
250     whiteResult = RESULT_DRAW;
251     break;
252   case END_ADJABORT:
253     sprintf(tmp, "Game aborted by adjudication} *");
254     whiteResult = RESULT_ABORT;
255     break;
256   default:
257     sprintf(tmp, "Hmm, the game ended and I don't know why} *");
258     break;
259   }
260   strcat(outstr, tmp);
261
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);
267           strcat(outstr, tmp);
268   }
269
270   strcat(outstr, "\n");
271
272   if (gg->rated && rate_change && gg->type != TYPE_BUGHOUSE)
273     /* Adjust ratings; bughouse gets done later. */
274     rating_update(g, -1);
275
276   if (beingplayed) {
277     int printed = 0;
278     int avail_printed = 0;
279
280     pprintf_noformat(gg->white, outstr);
281     pprintf_noformat(gg->black, outstr);
282     Bell (gg->white);
283     Bell (gg->black);
284
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);
291         print_avail = 1;
292       }
293       if (CheckPFlag(game_globals.garray[gl].black, PFLAG_OPEN)) {
294         getavailmess (game_globals.garray[gl].black, avail_bugblack);
295         print_avail = 1;
296       }
297       if ((gg->rated) && (rate_change)) {
298         /* Adjust ratings */
299         rating_update(g, gl);
300       }
301       game_ended(gl, CToggle(winner), why);
302     }
303
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);
307       print_avail = 1;
308     } else {    /* Part of an ongoing simul!  Let's shrink the array. */
309       
310     }
311     
312     if (CheckPFlag(gg->black, PFLAG_OPEN)) {
313       getavailmess (gg->black,avail_black);
314       print_avail = 1;
315     }
316
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))
320         continue;
321       if (pp->status != PLAYER_PROMPT)
322         continue;
323
324       if (CheckPFlag(p, PFLAG_GIN) || player_is_observe(p, g)) {
325         pprintf_noformat(p, outstr);
326         printed = 1;
327       }
328
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);
332           avail_printed = 1;
333         }
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);
336           avail_printed = 1;
337         }
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);
341             avail_printed = 1;
342           }
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);
345             avail_printed = 1;
346           }
347         }
348         if (avail_printed) {
349           avail_printed = 0;
350           printed = 1; 
351           pprintf (p,"\n");
352         }
353       }
354
355       if (printed) {
356         send_prompt(p);
357         printed = 0;
358       }
359     }
360
361     if (!(gg->rated && rate_change)) {
362       pprintf(gg->white, "No ratings adjustment done.\n");
363       pprintf(gg->black, "No ratings adjustment done.\n");
364     } 
365   }
366
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");
372   }
373   if (CheckPFlag(gg->black, PFLAG_AUTOMAIL)) {
374     pcommand(gg->black, "mailmoves");
375   }
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);
382   }
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);
387   if (beingplayed) {
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);
399   }
400   game_finish(g); 
401 }
402
403 static int was_promoted(struct game *g, int f, int r)
404 {
405 #define BUGHOUSE_PAWN_REVERT 1
406 #ifdef BUGHOUSE_PAWN_REVERT
407   int i;
408
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)
412         return 1;
413       if (g->moveList[i].fromFile == ALG_DROP)
414         return 0;
415       f = g->moveList[i].fromFile;
416       r = g->moveList[i].fromRank;
417     }
418   }
419 #endif
420   return 0;
421 }
422
423 int pIsPlaying (int p)
424 {
425         struct player *pp = &player_globals.parray[p];
426         int g = pp->game;
427         int p1 = pp->opponent;
428         
429         if (g < 0 || game_globals.garray[g].status != GAME_ACTIVE) {
430                 pprintf (p, "You are not playing a game.\n");
431                 return 0;
432         } 
433
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);
439                 pp->game = -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;
444                 }
445                 return 0;
446         }
447         return 1;
448 }
449
450 /* add clock increments */
451 static void game_add_increment(struct player *pp, struct game *gg)
452 {
453         /* no update on first move */
454         if (gg->game_state.moveNum == 1) return;
455
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
460                                                                                                    tenth secs */
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
464                                                                                                    tenth secs */
465                 }
466         } else {
467                 if (gg->game_state.onMove == BLACK) {
468                         gg->bTime += gg->bIncrement;
469                 }
470                 if (gg->game_state.onMove == WHITE) {
471                         gg->wTime += gg->wIncrement;
472                 }
473         }
474 }
475
476 /* updates clocks for a game with timeseal */
477 void timeseal_update_clocks(struct player *pp, struct game *gg)
478 {
479         /* no update on first move */
480         if (gg->game_state.moveNum == 1) return;
481
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;
491                 } else {
492                         gg->wRealTime -= gg->wTimeWhenMoved - gg->wTimeWhenReceivedMove;
493                 }
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;
503                 } else {
504                         gg->bRealTime -= gg->bTimeWhenMoved - gg->bTimeWhenReceivedMove;
505                 }
506         }
507 }
508
509
510 void process_move(int p, char *command)
511 {
512   struct player *pp = &player_globals.parray[p];
513   struct game *gg;
514   int g, result, len, i;
515   struct move_t move;
516   unsigned now = 0;
517
518   if (pp->game < 0) {
519     pprintf(p, "You are not playing or examining a game.\n");
520     return;
521   }
522   decline_withdraw_offers(p, -1, -PEND_SIMUL,DO_DECLINE);
523
524   g = pp->game;
525   gg = &game_globals.garray[g];
526
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");
531     } else
532     send_board_to(g, p); 
533     return;
534   }
535
536   if (gg->status != GAME_EXAMINE) {
537     if (!pIsPlaying(p)) return;
538
539     if (pp->side != gg->game_state.onMove) {
540       pprintf(p, "It is not your move.\n");
541       return;
542     }
543     if (gg->clockStopped) {
544       pprintf(p, "Game clock is paused, use \"unpause\" to resume.\n");
545       return;
546     }
547   }
548   if ((len = strlen(command)) > 1) {
549     if (command[len - 2] == '=') {
550       switch (tolower(command[strlen(command) - 1])) {
551       case 'n':
552         pp->promote = KNIGHT;
553         break;
554       case 'b':
555         pp->promote = BISHOP;
556         break;
557       case 'r':
558         pp->promote = ROOK;
559         break;
560       case 'q':
561         pp->promote = QUEEN;
562         break;
563       default:
564         pprintf(p, "Don't understand that move.\n");
565         return;
566         break;
567       }
568     }
569   }
570   switch (parse_move(command, &gg->game_state, &move, pp->promote)) {
571   case MOVE_ILLEGAL:
572     pprintf(p, "Illegal move.\n");
573     return;
574     break;
575   case MOVE_AMBIGUOUS:
576     pprintf(p, "Ambiguous move.\n");
577     return;
578     break;
579   default:
580     break;
581   }
582
583   if (gg->status == GAME_EXAMINE) {
584     gg->numHalfMoves++;
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);
588     }
589     result = execute_move(&gg->game_state, &move, 1);
590     move.atTime = now;
591     move.tookTime = 0;
592     MakeFENpos(g, move.FENpos);
593     gg->examMoveList[gg->numHalfMoves - 1] = move;
594     /* roll back time */
595     if (gg->game_state.onMove == WHITE) {
596       gg->wTime += (gg->lastDecTime - gg->lastMoveTime);
597     } else {
598       gg->bTime += (gg->lastDecTime - gg->lastMoveTime);
599     }
600     now = tenth_secs();
601     if (gg->numHalfMoves == 0)
602       gg->timeOfStart = now;
603     gg->lastMoveTime = now;
604     gg->lastDecTime = now;
605
606   } else {                      /* real game */
607     i = pp->opponent;
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");
611       return;
612     }
613     if (net_globals.con[pp->socket]->timeseal) {        /* does he use timeseal? */
614             timeseal_update_clocks(pp, &game_globals.garray[g]);
615     }
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
619        the timings */
620     if (pp->side == WHITE) {
621       gg->bTimeWhenReceivedMove = 0;
622     } else {
623       gg->wTimeWhenReceivedMove = 0;
624     }
625
626     game_update_time(g);
627     game_add_increment(pp, gg);
628
629     /* Do the move */
630     gg->numHalfMoves++;
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);
634     }
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);
641       else
642         update_holding(gg->link, move.pieceCaptured);
643     }
644     now = tenth_secs();
645     move.atTime = now;
646     if (gg->numHalfMoves > 1) {
647       move.tookTime = move.atTime - gg->lastMoveTime;
648     } else {
649       move.tookTime = move.atTime - gg->startTime;
650     }
651     gg->lastMoveTime = now;
652     gg->lastDecTime = now;
653     move.wTime = gg->wTime;
654     move.bTime = gg->bTime;
655
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;
660       } else {
661         move.tookTime = (game_globals.garray[pp->game].bTimeWhenMoved -
662                          game_globals.garray[pp->game].bTimeWhenReceivedMove) / 100;
663       }
664     }
665
666     if (gg->numHalfMoves <= 2) {
667             move.tookTime = 0;
668     }
669
670     MakeFENpos(g, move.FENpos);
671     gg->moveList[gg->numHalfMoves - 1] = move;
672   }
673
674   send_boards(g);
675
676   if (result == MOVE_ILLEGAL) {
677     pprintf(p, "Internal error, illegal move accepted!\n");
678   }
679   if ((result == MOVE_OK) && (gg->status == GAME_EXAMINE)) {
680     int p1;
681
682     for (p1 = 0; p1 < player_globals.p_num; p1++) {
683       if (player_globals.parray[p1].status != PLAYER_PROMPT)
684         continue;
685       if (player_is_observe(p1, g) || player_globals.parray[p1].game == g) {
686         pprintf(p1, "%s moves: %s\n", pp->name, move.algString);
687       }
688     }
689   }
690   if (result == MOVE_CHECKMATE) {
691     if (gg->status == GAME_EXAMINE) {
692       int p1;
693
694       for (p1 = 0; p1 < player_globals.p_num; p1++) {
695         if (player_globals.parray[p1].status != PLAYER_PROMPT)
696           continue;
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");
700         }
701       }
702     } else {
703       game_ended(g, CToggle(gg->game_state.onMove), END_CHECKMATE);
704     }
705   }
706   if (result == MOVE_STALEMATE) {
707     if (gg->status == GAME_EXAMINE) {
708       int p1;
709
710       for (p1 = 0; p1 < player_globals.p_num; p1++) {
711         if (player_globals.parray[p1].status != PLAYER_PROMPT)
712           continue;
713         if (player_is_observe(p1, g) || player_globals.parray[p1].game == g) {
714           pprintf(p1, "Stalemate.\n");
715         }
716       }
717     } else {
718       game_ended(g, CToggle(gg->game_state.onMove), END_STALEMATE);
719     }
720   }
721   if (result == MOVE_NOMATERIAL) {
722     if (gg->status == GAME_EXAMINE) {
723       int p1;
724
725       for (p1 = 0; p1 < player_globals.p_num; p1++) {
726         if (player_globals.parray[p1].status != PLAYER_PROMPT)
727           continue;
728         if (player_is_observe(p1, g) || player_globals.parray[p1].game == g) {
729           pprintf(p1, "No mating material.\n");
730         }
731       }
732     } else {
733       game_ended(g, CToggle(gg->game_state.onMove), END_NOMATERIAL);
734     }
735   }
736 }
737
738 int com_resign(int p, param_list param)
739 {
740   struct player *pp = &player_globals.parray[p];
741   int g, o, oconnected;
742
743   if (param[0].type == TYPE_NULL) {
744     g = pp->game;
745     if (!pIsPlaying(p))
746       return COM_OK;
747     else {
748       decline_withdraw_offers(p, -1, -1, DO_DECLINE);
749       game_ended(g, (game_globals.garray[g].white == p) ? BLACK : WHITE, END_RESIGN);
750     }
751   } else if (FindPlayer(p, param[0].val.word, &o, &oconnected)) {
752     g = game_new();
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);
756         if (!oconnected)
757           player_remove(o);
758         return COM_OK;
759       } else {
760         game_globals.garray[g].white = o;
761         game_globals.garray[g].black = p;
762       }
763     } else {
764       game_globals.garray[g].white = p;
765       game_globals.garray[g].black = o;
766     }
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);
774     if (!oconnected)
775       player_remove(o);
776   }
777   return COM_OK;
778 }
779
780 static int Check50MoveRule (int p, int g)
781 {
782   int num_reversible = game_globals.garray[g].numHalfMoves;
783
784   if (game_globals.garray[g].game_state.lastIrreversable >= 0) {
785     num_reversible -= game_globals.garray[g].game_state.lastIrreversable;
786   }
787   if (num_reversible > 99) {
788     game_ended(g, (game_globals.garray[g].white == p) ? BLACK : WHITE, END_50MOVERULE);
789     return 1;
790   }
791   return 0;
792 }
793
794 static char *GetFENpos (int g, int half_move)
795 {
796   if (half_move < 0)
797     return game_globals.garray[g].FENstartPos;
798   else return game_globals.garray[g].moveList[half_move].FENpos;
799 }
800
801 static int CheckRepetition (int p, int g)
802 {
803   struct player *pp = &player_globals.parray[p];
804   struct pending* pend;
805   int move_num;
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);
809   char *pos;
810
811   if (game_globals.garray[g].numHalfMoves < 8)  /* can't have three repeats any quicker. */
812     return 0;
813
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))
818       flag1++;
819     if (strlen(pos2) == strlen(pos) && !strcmp(pos2, pos))
820       flag2++;
821   }
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);
826     }
827     game_ended(g, (game_globals.garray[g].white == p) ? BLACK : WHITE, END_REPETITION);
828     return 1;
829   }
830   else return 0;
831 }
832
833 int com_draw(int p, param_list param)
834 {
835   struct player *pp = &player_globals.parray[p];
836   struct pending* pend;
837   int p1, g = pp->game;
838
839   if (!pIsPlaying(p)) {
840     return COM_OK;
841   }
842   if (Check50MoveRule (p, g) || CheckRepetition(p, g)) {
843     return COM_OK;
844   }
845   p1 = pp->opponent;
846
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");
850     return COM_OK;
851   }
852
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);
857   } else {
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);
863   }
864   return COM_OK;
865 }
866
867 int com_pause(int p, param_list param)
868 {
869   struct player *pp = &player_globals.parray[p];
870   int g, now;
871   struct pending* pend;
872
873   if (!pIsPlaying(p)) {
874     return COM_OK;
875   }
876   g = pp->game;
877   if (game_globals.garray[g].wTime == 0) {
878     pprintf(p, "You can't pause untimed games.\n");
879     return COM_OK;
880   }
881   if (game_globals.garray[g].clockStopped) {
882     pprintf(p, "Game is already paused, use \"unpause\" to resume.\n");
883     return COM_OK;
884   }
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);
891     } else {
892       game_globals.garray[g].bTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
893     }
894     now = tenth_secs();
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;
899     send_boards(g);
900     pprintf_prompt(pp->opponent, "\n%s accepted pause. Game clock paused.\n",
901                    pp->name);
902     pprintf(p, "Game clock paused.\n");
903   } else {
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);
909   }
910   return COM_OK;
911 }
912
913 int com_unpause(int p, param_list param)
914 {
915   struct player *pp = &player_globals.parray[p];
916   int g;
917   int now;
918   struct pending* pend;
919
920   if (!pIsPlaying(p)) {
921     return COM_OK;
922   }
923
924   g = pp->game;
925
926   if (!game_globals.garray[g].clockStopped) {
927     pprintf(p, "Game is not paused.\n");
928     return COM_OK;
929   }
930   if ((pend = find_pend(pp->opponent, p, PEND_UNPAUSE)) != NULL) {
931     delete_pending(pend);
932     game_globals.garray[g].clockStopped = 0;
933     now = tenth_secs();
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;
938     send_boards(g);
939     pprintf(p, "Game clock resumed.\n");
940     pprintf_prompt(pp->opponent, "\nGame clock resumed.\n");
941   } else {
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);
947   }
948   return COM_OK;
949 }
950
951 int com_abort(int p, param_list param)
952 {
953   struct player *pp = &player_globals.parray[p];
954   struct pending* pend;
955   int p1, g, myColor, yourColor, myGTime, yourGTime;
956   int courtesyOK = 1;
957
958   g = pp->game;
959   if (!pIsPlaying(p))
960     return COM_OK;
961
962   p1 = pp->opponent;
963   if (p == game_globals.garray[g].white) {
964     myColor = WHITE;
965     yourColor = BLACK;
966     myGTime = game_globals.garray[g].wTime;
967     yourGTime = game_globals.garray[g].bTime;
968   } else {
969     myColor = BLACK;
970     yourColor = WHITE;
971     myGTime = game_globals.garray[g].bTime;
972     yourGTime = game_globals.garray[g].wTime;
973   }
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");
978     return COM_OK;
979   }
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);
984   } else {
985     game_update_time(g);
986
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);
996     }
997
998     if (net_globals.con[player_globals.parray[p1].socket]->timeseal) {  /* opp uses timeseal? */
999
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. */
1004         courtesyOK = 0;
1005
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");
1013           return COM_OK;
1014         }
1015       }
1016     }
1017
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);
1024     } else {
1025       pprintf(p1, "\n");
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);
1031     }
1032   }
1033   return COM_OK;
1034 }
1035
1036 static int player_has_mating_material(struct game_state_t *gs, int color)
1037 {
1038   int i, j;
1039   int piece;
1040   int minor_pieces = 0;
1041
1042   for (i = 0; i < 8; i++)
1043     for (j = 0; j < 8; j++) {
1044       piece = gs->board[i][j];
1045       switch (piecetype(piece)) {
1046       case BISHOP:
1047       case KNIGHT:
1048         if (iscolor(piece, color))
1049           minor_pieces++;
1050         break;
1051       case KING:
1052       case NOPIECE:
1053         break;
1054       default:
1055         if (iscolor(piece, color))
1056           return 1;
1057       }
1058     }
1059   return ((minor_pieces > 1) ? 1 : 0);
1060 }
1061
1062 int com_flag(int p, param_list param)
1063 {
1064         struct player *pp = &player_globals.parray[p];
1065         struct game *gg;
1066         int g;
1067         int myColor;
1068
1069         if (!pIsPlaying(p)) {
1070                 return COM_OK;
1071         }
1072         g = pp->game;
1073
1074         gg = &game_globals.garray[g];
1075
1076         myColor = (p == gg->white ? WHITE : BLACK);
1077         if (gg->type == TYPE_UNTIMED) {
1078                 pprintf(p, "You can't flag an untimed game.\n");
1079                 return COM_OK;
1080         }
1081         if (gg->numHalfMoves < 2) {
1082                 pprintf(p, "You cannot flag before both players have moved.\nUse abort instead.\n");
1083                 return COM_OK;
1084         }
1085         game_update_time(g);
1086         
1087         {
1088                 int myTime, yourTime, opp = pp->opponent, serverTime;
1089                 
1090                 if (net_globals.con[pp->socket]->timeseal) {    /* does caller use timeseal? */
1091                         myTime = (myColor==WHITE?gg->wRealTime:gg->bRealTime);
1092                 } else {
1093                         myTime = (myColor == WHITE?gg->wTime:gg->bTime);
1094                 }
1095                 serverTime = (myColor == WHITE?gg->bTime:gg->wTime);
1096                 
1097                 if (net_globals.con[player_globals.parray[opp].socket]->timeseal) {     /* opp uses timeseal? */
1098                         yourTime = (myColor == WHITE?gg->bRealTime:gg->wRealTime);
1099                 } else {
1100                         yourTime = serverTime;
1101                 }
1102
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);
1107                         return COM_OK;
1108                 }
1109
1110                 if (yourTime > 0) {
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. */
1114                         
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");
1123                                 return COM_OK;
1124                         }
1125                         
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). */
1133                         
1134                         pprintf(p, "Your opponent is not out of time!\n");
1135                         return COM_OK;
1136                 }
1137         }
1138         
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);
1142         else
1143                 game_ended(g, myColor, END_FLAGNOMATERIAL);
1144         return COM_OK;
1145 }
1146
1147 int com_adjourn(int p, param_list param)
1148 {
1149   struct player *pp = &player_globals.parray[p];
1150   struct pending* pend;
1151   int p1, g, myColor, yourColor;
1152
1153   if (!pIsPlaying(p))
1154     return COM_OK;
1155
1156   p1 = pp->opponent;
1157   g = pp->game;
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");
1160     return COM_OK;
1161   }
1162   if (game_globals.garray[g].link >= 0) {
1163     pprintf(p, "Bughouse games cannot be adjourned.\n");
1164     return COM_OK;
1165   }
1166   myColor = (p == game_globals.garray[g].white ? WHITE : BLACK);
1167   yourColor = (myColor == WHITE ? BLACK : WHITE);
1168
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);
1173   } else {
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);
1182     } else {
1183       pprintf(p1, "\n");
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);
1189     }
1190   }
1191   return COM_OK;
1192 }
1193
1194 int com_takeback(int p, param_list param)
1195 {
1196   struct player *pp = &player_globals.parray[p];
1197   int nHalfMoves = 1, g, i, p1, pend_half_moves;
1198   struct pending* from;
1199
1200   if (!pIsPlaying(p))
1201     return COM_OK;
1202
1203   p1 = pp->opponent;
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] !=
1207         pp->game)) {
1208     pprintf(p, "You can only make requests when the simul player is at your board.\n");
1209     return COM_OK;
1210   }
1211
1212   g = pp->game;
1213   if (game_globals.garray[g].link >= 0) {
1214     pprintf(p, "Takeback not implemented for bughouse games yet.\n");
1215     return COM_OK;
1216   }
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");
1221       return COM_OK;
1222     }
1223   }
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);
1234           break;
1235         }
1236       }
1237
1238       game_globals.garray[g].wTimeWhenReceivedMove = 0;
1239       game_globals.garray[g].bTimeWhenReceivedMove = 0;
1240
1241       send_boards(g);
1242     } else {
1243
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", 
1247                        pp->name);
1248         return COM_OK;
1249       }
1250  
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", 
1254                        pp->name);
1255         return COM_OK;
1256       }
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;
1262     }
1263   } else {
1264
1265     if (!game_globals.garray[g].numHalfMoves) {
1266       pprintf(p, "There are no moves in your game.\n");
1267       return COM_OK;
1268     }
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);
1271       return COM_OK;
1272     }
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",
1276            nHalfMoves);
1277     pprintf(p, "Takeback request sent.\n");
1278     from = add_request(p, pp->opponent, PEND_TAKEBACK);
1279     from->wtime = nHalfMoves;
1280   }
1281   return COM_OK;
1282 }
1283
1284
1285 int com_switch(int p, param_list param)
1286 {
1287   struct player *pp = &player_globals.parray[p];
1288   int g = pp->game, tmp, now, p1;
1289   char *strTmp;
1290   struct pending* pend;
1291
1292   if (!pIsPlaying(p))
1293     return COM_OK;
1294
1295   p1 = pp->opponent;
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");
1299     return COM_OK;
1300   }
1301
1302   if (game_globals.garray[g].link >= 0) {
1303     pprintf(p, "Switch not implemented for bughouse games.\n");
1304     return COM_OK;
1305   }
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);
1310
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);
1318     free(strTmp);
1319
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);
1325     } else {
1326       game_globals.garray[g].bTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
1327     }
1328     now = tenth_secs();
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;
1333     send_boards(g);
1334     return COM_OK;
1335   }
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");
1338     return COM_OK;
1339   }
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);
1345   return COM_OK;
1346 }
1347
1348 int com_time(int p, param_list param)
1349 {
1350   struct player *pp = &player_globals.parray[p];
1351   int p1, g;
1352
1353   if (param[0].type == TYPE_NULL) {
1354     g = pp->game;
1355     if (!pIsPlaying(p))
1356       return COM_OK;
1357   } else {
1358     g = GameNumFromParam(p, &p1, &param[0]);
1359     if (g < 0)
1360       return COM_OK;
1361   }
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");
1364     return COM_OK;
1365   }
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);
1375   return COM_OK;
1376 }
1377
1378 int com_ptime(int p, param_list param)
1379 {
1380   struct player *pp = &player_globals.parray[p];
1381   int retval, part = pp->partner;
1382
1383   if (part < 0) {
1384     pprintf(p, "You do not have a partner.\n");
1385     return COM_OK;
1386   }
1387   retval = pcommand (p, "time %s", player_globals.parray[part].name);
1388   if (retval == COM_OK)
1389     return COM_OK_NOPROMPT;
1390   else
1391     return retval;
1392 }
1393
1394 int com_boards(int p, param_list param)
1395 {
1396   char *category = NULL;
1397   char dname[MAX_FILENAME_SIZE];
1398   DIR *dirp;
1399   struct dirent *dp;
1400
1401   if (param[0].type == TYPE_WORD)
1402     category = param[0].val.word;
1403   if (category) {
1404     pprintf(p, "Boards Available For Category %s:\n", category);
1405     sprintf(dname, "%s/%s", BOARD_DIR, category);
1406   } else {
1407     pprintf(p, "Categories Available:\n");
1408     sprintf(dname, "%s", BOARD_DIR);
1409   }
1410   dirp = opendir(dname);
1411   if (!dirp) {
1412     pprintf(p, "No such category %s, try \"boards\".\n", category);
1413     return COM_OK;
1414   }
1415
1416 /* YUK! what a mess, how about printing an ordered directory? - DAV*/
1417
1418   for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
1419     if (!strcmp(dp->d_name, "."))
1420       continue;
1421     if (!strcmp(dp->d_name, ".."))
1422       continue;
1423     pprintf(p, "%s\n", dp->d_name);
1424   }
1425   closedir(dirp);
1426   return COM_OK;
1427 }
1428
1429 int com_simmatch(int p, param_list param)
1430 {
1431   struct player *pp = &player_globals.parray[p];
1432   int p1, g, adjourned;
1433   int num;
1434   char tmp[100];
1435   struct pending* pend;
1436   char* board = NULL;
1437   char* category = NULL;
1438   char fname[MAX_FILENAME_SIZE];
1439
1440   if (pp->game >=0) {
1441     if (game_globals.garray[pp->game].status == GAME_EXAMINE) {
1442       pprintf(p, "You are still examining a game.\n");
1443       return COM_OK;
1444     }
1445     if (game_globals.garray[pp->game].status == GAME_SETUP) {
1446       pprintf(p, "You are still setting up a position.\n");
1447       return COM_OK;
1448     }
1449   } 
1450   p1 = player_find_part_login(param[0].val.word);
1451   if (p1 < 0) {
1452     pprintf(p, "No user named \"%s\" is logged in.\n", param[0].val.word);
1453     return COM_OK;
1454   }
1455   if (p == p1) {
1456     pprintf(p, "You can't simmatch yourself!\n");
1457     return COM_OK;
1458   }
1459   if ((pend = find_pend(p1, p, PEND_SIMUL)) != NULL) {
1460
1461     /* Accepting Simul ! */
1462
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);
1468       return COM_OK;
1469     }
1470     unobserveAll(p);            /* stop observing when match starts */
1471     unobserveAll(p1);
1472
1473     g = game_new();
1474     adjourned = 0;
1475     if (game_read(g, p, p1) >= 0) {
1476       adjourned = 1;
1477       delete_pending(pend);
1478     }
1479
1480     if (!adjourned) {           /* no adjourned game, so begin a new game */
1481
1482       if ((pend->category != NULL) && (pend->board_type != NULL)) {
1483         board = strdup(pend->category);
1484         category = strdup(pend->board_type);
1485       } 
1486
1487       delete_pending(pend);
1488
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");
1492         game_remove(g);
1493
1494         if (board != NULL) {
1495           free (board);
1496           free (category);
1497         }
1498         return COM_OK;
1499       }
1500
1501       if (board != NULL) {
1502         free (board);
1503         free (category);
1504       }
1505
1506     } else {                    /* resume adjourned game */
1507       game_delete(p, p1);
1508
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]);
1510       pprintf(p, tmp);
1511       pprintf(p1, tmp);
1512
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;
1519       pp->game = g;
1520       pp->opponent = p1;
1521       pp->side = WHITE;
1522       player_globals.parray[p1].game = g;
1523       player_globals.parray[p1].opponent = p;
1524       player_globals.parray[p1].side = BLACK;
1525       send_boards(g);
1526     }
1527
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;
1534     }
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);
1542     else
1543       pp->simul_info->onBoard = 0;
1544     return COM_OK;
1545   }
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");
1548     return COM_OK;
1549   }
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");
1553       return COM_OK;
1554     }
1555   }
1556   if (pp->game >=0) {
1557     pprintf(p, "You are already playing a game.\n");
1558     return COM_OK;
1559   }
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");
1563     return COM_OK;
1564   }
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);
1568     return COM_OK;
1569   }
1570
1571 /* loon: checking for some crazy situations we can't allow :) */
1572
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");
1579     } else {
1580       pprintf(p, " can't begin a simul while playing a non-simul game.\n");
1581     }
1582     return COM_OK;
1583   }
1584
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;
1587   if (adjourned) {
1588     if (!(game_globals.garray[g].type == TYPE_UNTIMED))
1589       adjourned = 0;
1590   }
1591   game_remove(g);
1592
1593   pend = add_request(p, p1, PEND_SIMUL);
1594
1595   if ((param[1].type == TYPE_WORD) && (param[2].type == TYPE_WORD)) {
1596
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);
1600       return COM_OK;
1601     }
1602     pend->category = strdup(param[1].val.word);
1603     pend->board_type = strdup(param[2].val.word);
1604   } else {
1605     pend->category = NULL;
1606     pend->board_type = NULL;
1607   }
1608  
1609   pprintf(p1, "\n");
1610   pprintf_highlight(p1, "%s", pp->name);
1611   if (adjourned) {
1612     pprintf_prompt(p1, " requests to continue an adjourned simul game.\n");
1613     pprintf(p, "Request to resume simul sent. Adjourned game found.\n");
1614   } else {
1615     if (pend->category == NULL)
1616       pprintf_prompt(p1, " requests to join a simul match with you.\n");
1617     else
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");
1621   }
1622   return COM_OK;
1623 }
1624
1625 int com_goboard(int p, param_list param)
1626 {
1627   struct player *pp = &player_globals.parray[p];
1628   int on, g, p1, gamenum;
1629
1630   if (pp->simul_info == NULL) {
1631     pprintf(p, "You are not giving a simul.\n");
1632     return COM_OK;
1633   }
1634
1635   if (!pp->simul_info->numBoards) {
1636     pprintf(p, "You are not giving a simul.\n");
1637     return COM_OK;
1638   }
1639
1640   if (param[0].type == TYPE_WORD) {
1641
1642     p1 = player_find_part_login(param[0].val.word);
1643     if (p1 < 0) {
1644       pprintf(p, "No user named \"%s\" is logged in.\n", param[0].val.word);
1645       return COM_OK;
1646     }
1647     if (p == p1) {
1648       pprintf(p, "You can't goboard yourself!\n");
1649       return COM_OK;
1650     }
1651
1652     gamenum = player_globals.parray[p1].game;
1653     if (gamenum < 0) {
1654       pprintf (p,"%s is not playing a game.\n", player_globals.parray[p1].login);
1655       return COM_OK;
1656     }
1657
1658   } else { 
1659     gamenum = param[0].val.integer - 1;
1660     if (gamenum < 0)
1661       gamenum = 0;
1662   }
1663
1664   on = pp->simul_info->onBoard;
1665   g = pp->simul_info->boards[on];
1666   if (gamenum == g) {
1667     pprintf(p, "You are already at that board!\n");
1668     return COM_OK;
1669   }
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) {
1673       if (g >= 0) {
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");
1677       }
1678     } else
1679     pprintf(p, "You are not playing that game/person.\n");
1680   } else
1681     pprintf(p, "You are only playing one board!\n");
1682   return COM_OK;
1683 }
1684
1685 int com_simnext(int p, param_list param)
1686 {
1687   struct player *pp = &player_globals.parray[p];
1688   int on, g;
1689
1690   if (pp->simul_info == NULL) {
1691     pprintf(p, "You are not giving a simul.\n");
1692     return COM_OK;
1693   }
1694
1695   if (!pp->simul_info->numBoards) {
1696     pprintf(p, "You are not giving a simul.\n");
1697     return COM_OK;
1698   }
1699
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];
1704     if (g >= 0) {
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);
1709     }
1710   } else
1711     pprintf(p, "You are only playing one board!\n");
1712   return COM_OK;
1713 }
1714
1715 int com_simprev(int p, param_list param)
1716 {
1717   struct player *pp = &player_globals.parray[p];
1718   int on, g;
1719
1720   if (pp->simul_info == NULL) {
1721     pprintf(p, "You are not giving a simul.\n");
1722     return COM_OK;
1723   }
1724
1725   if (!pp->simul_info->numBoards) {
1726     pprintf(p, "You are not giving a simul.\n");
1727     return COM_OK;
1728   }
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];
1733     if (g >= 0) {
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");
1737     }
1738     player_goto_prev_board(p);
1739   } else
1740     pprintf(p, "You are only playing one board!\n");
1741   return COM_OK;
1742 }
1743
1744 int com_simgames(int p, param_list param)
1745 {
1746   int p1 = p;
1747
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);
1751       return COM_OK;
1752     }
1753   }
1754   if (p1 == p)
1755     pprintf(p, "You are playing %d simultaneous games.\n",
1756             player_num_active_boards(p1));
1757   else
1758     pprintf(p, "%s is playing %d simultaneous games.\n", player_globals.parray[p1].name,
1759             player_num_active_boards(p1));
1760   return COM_OK;
1761 }
1762
1763 int com_simpass(int p, param_list param)
1764 {
1765   struct player *pp = &player_globals.parray[p];
1766   int g, p1, on;
1767
1768   if (!pIsPlaying(p))
1769     return COM_OK;
1770
1771   g = pp->game;
1772   p1 = game_globals.garray[g].white;
1773
1774   if (player_globals.parray[p1].simul_info == NULL) {
1775     pprintf(p, "You are not participating in a simul.\n");
1776     return COM_OK;
1777   }
1778
1779   if (!player_globals.parray[p1].simul_info->numBoards) {
1780     pprintf(p, "You are not participating in a simul.\n");
1781     return COM_OK;
1782   }
1783   if (p == p1) {
1784     pprintf(p, "You are the simul holder and cannot pass!\n");
1785     return COM_OK;
1786   }
1787   if (player_num_active_boards(p1) == 1) {
1788     pprintf(p, "This is the only game, so passing is futile.\n");
1789     return COM_OK;
1790   }
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");
1794     return COM_OK;
1795   }
1796   if (game_globals.garray[g].passes >= MAX_SIMPASS) {
1797     Bell (p);
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");
1802     return COM_OK;
1803   }
1804   decline_withdraw_offers(p, -1, -PEND_SIMUL,DO_DECLINE);
1805
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);
1813   return COM_OK;
1814 }
1815
1816 int com_simabort(int p, param_list param)
1817 {
1818   struct player *pp = &player_globals.parray[p];
1819
1820   if (pp->simul_info == NULL) {
1821     pprintf(p, "You are not giving a simul.\n");
1822     return COM_OK;
1823   }
1824
1825   if (!pp->simul_info->numBoards) {
1826     pprintf(p, "You are not giving a simul.\n");
1827     return COM_OK;
1828   }
1829   decline_withdraw_offers(p, -1, -PEND_SIMUL,DO_DECLINE);
1830   game_ended(pp->simul_info->boards[pp->simul_info->onBoard],
1831              WHITE, END_ABORT);
1832   return COM_OK;
1833 }
1834
1835 int com_simallabort(int p, param_list param)
1836 {
1837   struct player *pp = &player_globals.parray[p];
1838   int i;
1839
1840   if (pp->simul_info == NULL) {
1841     pprintf(p, "You are not giving a simul.\n");
1842     return COM_OK;
1843   }
1844
1845   if (!pp->simul_info->numBoards) {
1846     pprintf(p, "You are not giving a simul.\n");
1847     return COM_OK;
1848   }
1849
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],
1854                  WHITE, END_ABORT);
1855
1856   return COM_OK;
1857 }
1858
1859 int com_simadjourn(int p, param_list param)
1860 {
1861   struct player *pp = &player_globals.parray[p];
1862
1863   if (pp->simul_info == NULL) {
1864     pprintf(p, "You are not giving a simul.\n");
1865     return COM_OK;
1866   }
1867
1868   if (!pp->simul_info->numBoards) {
1869     pprintf(p, "You are not giving a simul.\n");
1870     return COM_OK;
1871   }
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);
1875   return COM_OK;
1876 }
1877
1878 int com_simalladjourn(int p, param_list param)
1879 {
1880   struct player *pp = &player_globals.parray[p];
1881   int i;
1882
1883   if (pp->simul_info == NULL) {
1884     pprintf(p, "You are not giving a simul.\n");
1885     return COM_OK;
1886   }
1887
1888   if (!pp->simul_info->numBoards) {
1889     pprintf(p, "You are not giving a simul.\n");
1890     return COM_OK;
1891   }
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);
1897
1898   return COM_OK;
1899 }
1900
1901 int com_moretime(int p, param_list param)
1902 {
1903   struct player *pp = &player_globals.parray[p];
1904   int g, increment;
1905
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");
1909     return COM_OK;
1910   }
1911   increment = param[0].val.integer;
1912   if (increment <= 0) {
1913     pprintf(p, "Moretime requires an integer value greater than zero.\n");
1914     return COM_OK;
1915   }
1916   if (!pIsPlaying(p))
1917     return COM_OK;
1918  
1919   if (increment > 600) {
1920     pprintf(p, "Moretime has a maximum limit of 600 seconds.\n");
1921     increment = 600;
1922   }
1923   g = pp->game;
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",
1928             increment);
1929     pprintf_prompt(pp->opponent,
1930                    "\nYour opponent has added %d seconds to your clock.\n",
1931                    increment);
1932   }
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",
1937             increment);
1938     pprintf_prompt(pp->opponent,
1939                    "\nYour opponent has added %d seconds to your clock.\n",
1940                    increment);
1941   }
1942   return COM_OK;
1943 }
1944