1 /*
2  * set.c
3  *
4  * by Gary Wong <gtw@gnu.org>, 1999, 2000, 2001, 2002.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of version 3 or later of the GNU General Public License as
8  * published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  * $Id: set.c,v 1.407 2018/05/10 17:38:48 plm Exp $
20  */
21 
22 #include "config.h"
23 #include "gtklocdefs.h"
24 
25 #ifdef WIN32
26 /* Needed for thread priority defines */
27 #include <winsock2.h>
28 #include <windows.h>
29 #endif
30 
31 #include <glib.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #include <stdlib.h>
35 
36 #if defined(HAVE_SYS_RESOURCE_H)
37 #include <sys/resource.h>
38 #endif                          /* HAVE_SYS_RESOURCE_H */
39 
40 #if defined(HAVE_SOCKETS)
41 #ifndef WIN32
42 
43 #if defined(HAVE_SYS_SOCKET_H)
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #endif                          /* HAVE_SYS_SOCKET_H */
47 
48 #include <stdio.h>
49 #include <string.h>
50 
51 #else                           /* #ifndef WIN32 */
52 #include <winsock2.h>
53 #endif                          /* #ifndef WIN32 */
54 #endif                          /* #if HAVE_SOCKETS */
55 
56 #if defined(HAVE_UNISTD_H)
57 #include <unistd.h>
58 #endif                          /* HAVE_UNISTD_H */
59 
60 #include "backgammon.h"
61 #include "dice.h"
62 #include "eval.h"
63 #include "external.h"
64 #include "export.h"
65 
66 #if defined(USE_GTK)
67 #include "gtkgame.h"
68 #include "gtkprefs.h"
69 #include "gtkchequer.h"
70 #include "gtkwindows.h"
71 #endif                          /* USE_GTK */
72 
73 #include "matchequity.h"
74 #include "positionid.h"
75 #include "matchid.h"
76 #include "renderprefs.h"
77 #include "drawboard.h"
78 #include "format.h"
79 #include "boarddim.h"
80 #include "sound.h"
81 #include "openurl.h"
82 
83 #if defined(USE_BOARD3D)
84 #include "fun3d.h"
85 #endif
86 #include "multithread.h"
87 
88 static int iPlayerSet, iPlayerLateSet;
89 
90 static evalcontext *pecSet;
91 static char *szSet;
92 static const char *szSetCommand;
93 static rolloutcontext *prcSet;
94 
95 static evalsetup *pesSet;
96 
97 static rng *rngSet;
98 static rngcontext *rngctxSet;
99 
100 #if !defined(HAVE_LIBGMP)
101 
102 /* get the next token from the input and convert as an
103  * integer. Returns 0 on empty input or non-numerics found, and
104  * 1 on success. On failure, one token (if any were available)
105  * will have been consumed, it is not pushed back into the input.
106  * Unsigned long is returned in pretVal
107  */
108 static gboolean
ParseULong(char ** ppch,unsigned long * pretVal)109 ParseULong(char **ppch, unsigned long *pretVal)
110 {
111 
112     char *pch, *pchOrig;
113 
114     if (!ppch || !(pchOrig = NextToken(ppch)))
115         return FALSE;
116 
117     for (pch = pchOrig; *pch; pch++)
118         if (!isdigit(*pch))
119             return FALSE;
120 
121     errno = 0;                  /* To distinguish success/failure after call */
122     *pretVal = strtol(pchOrig, NULL, 10);
123 
124     /* Check for various possible errors */
125     if ((errno == ERANGE && (*pretVal == LONG_MAX || *pretVal == (unsigned long)
126                              LONG_MIN))
127         || (errno != 0 && *pretVal == 0))
128         return FALSE;
129 
130     return TRUE;
131 }
132 #endif
133 
134 static void
SetSeed(const rng rngx,void * rngctx,char * sz)135 SetSeed(const rng rngx, void *rngctx, char *sz)
136 {
137 
138     if (rngx == RNG_MANUAL || rngx == RNG_RANDOM_DOT_ORG || rngx == RNG_FILE) {
139         outputf(_("You can't set a seed if you're using %s as RNG\n"), aszRNG[rngx]);
140         return;
141     }
142 
143     if (sz && *sz) {
144 #if defined(HAVE_LIBGMP)
145         if (InitRNGSeedLong(sz, rngx, rngctx))
146             outputl(_("You must specify a valid seed (see `help set " "seed')."));
147         else
148             outputf(_("Seed set to %s.\n"), sz);
149 #else
150         gboolean bSuccess;
151         unsigned long n = 0;
152 
153         bSuccess = ParseULong(&sz, &n);
154 
155         if (!bSuccess || n > UINT_MAX) {
156             outputl(_("You must specify a valid seed (see `help set seed')."));
157 
158             return;
159         }
160 
161         InitRNGSeed((unsigned int) n, rngx, rngctx);
162         outputf(_("Seed set to %ld.\n"), n);
163 #endif                          /* HAVE_LIBGMP */
164     } else
165         outputl(RNGSystemSeed(rngx, rngctx, NULL) ?
166                 _("Seed initialised from system random data.") : _("Seed initialised by system clock."));
167 }
168 
169 extern void
SetRNG(rng * prng,rngcontext * rngctx,rng rngNew,char * szSeed)170 SetRNG(rng * prng, rngcontext * rngctx, rng rngNew, char *szSeed)
171 {
172 
173     if (*prng == rngNew && !*szSeed) {
174         outputf(_("You are already using the %s generator.\n"), gettext(aszRNG[rngNew]));
175         return;
176     }
177 
178     if (prng == &prcSet->rngRollout && (rngNew == RNG_MANUAL || rngNew == RNG_RANDOM_DOT_ORG || rngNew == RNG_FILE)) {
179         outputf(_("The %s RNG is not suitable for rollouts\n"), aszRNG[rngNew]);
180         return;
181     }
182 
183     /* Dispose internal paremeters for RNG */
184 
185     CloseRNG(*prng, rngctx);
186 
187     switch (rngNew) {
188     case RNG_BBS:
189 #if defined(HAVE_LIBGMP)
190         {
191             char *sz, *sz1;
192             int fInit;
193 
194             fInit = FALSE;
195 
196             if (*szSeed) {
197                 if (!StrNCaseCmp(szSeed, "modulus", strcspn(szSeed, " \t\n\r\v\f"))) {
198                     NextToken(&szSeed); /* skip "modulus" keyword */
199                     if (InitRNGBBSModulus(NextToken(&szSeed), rngctx)) {
200                         outputf(_("You must specify a valid modulus (see `help " "set rng bbs')."));
201                         return;
202                     }
203                     fInit = TRUE;
204                 } else if (!StrNCaseCmp(szSeed, "factors", strcspn(szSeed, " \t\n\r\v\f"))) {
205                     NextToken(&szSeed); /* skip "modulus" keyword */
206                     sz = NextToken(&szSeed);
207                     sz1 = NextToken(&szSeed);
208                     if (InitRNGBBSFactors(sz, sz1, rngctx)) {
209                         outputf(_("You must specify two valid factors (see `help " "set rng bbs')."));
210                         return;
211                     }
212                     fInit = TRUE;
213                 }
214             }
215 
216             if (!fInit)
217                 /* use default modulus, with factors
218                  * 148028650191182616877187862194899201391 and
219                  * 315270837425234199477225845240496832591. */
220                 InitRNGBBSModulus("46669116508701198206463178178218347698370"
221                                   "262771368237383789001446050921334081", rngctx);
222             break;
223         }
224 #else
225         abort();
226 #endif                          /* HAVE_LIBGMP */
227 
228     case RNG_FILE:
229         {
230             char *sz = NextToken(&szSeed);
231 
232             if (!sz || !*sz) {
233                 outputl(_("Please enter filename!"));
234                 return;
235             }
236 
237             if (!OpenDiceFile(rngctx, sz)) {
238                 outputf(_("File %s does not exist or is not readable"), sz);
239                 return;
240             }
241 
242         }
243         break;
244 
245 
246     default:
247         ;
248     }
249 
250     outputf(_("GNU Backgammon will now use the %s generator.\n"), gettext(aszRNG[rngNew]));
251 
252     switch ((*prng = rngNew)) {
253     case RNG_MANUAL:
254     case RNG_RANDOM_DOT_ORG:
255     case RNG_FILE:
256         /* no-op */
257         break;
258 
259     default:
260         SetSeed(*prng, rngctx, szSeed);
261         break;
262     }
263 
264 }
265 
266 
267 static void
SetMoveFilter(char * sz,movefilter aamf[MAX_FILTER_PLIES][MAX_FILTER_PLIES])268 SetMoveFilter(char *sz, movefilter aamf[MAX_FILTER_PLIES][MAX_FILTER_PLIES])
269 {
270 
271     int ply = ParseNumber(&sz);
272     int level;
273     int accept;
274     movefilter *pmfFilter;
275     int extras;
276     float tolerance;
277 
278     /* Temporary removing the temporary debug ...
279      * outputf( _("Temporary debug: '%s' '%s'\n"), szSetCommand, sz ); */
280 
281     if (ply < 0) {
282         outputl(N_("You must specify for which ply you want to set a filter"));
283         return;
284     }
285 
286     if (!(0 < ply && ply <= MAX_FILTER_PLIES)) {
287         outputf(_("You must specify a valid ply for setting move filters "
288                   "(see `help set %s movefilter')"), szSetCommand);
289         return;
290     }
291 
292     if (((level = ParseNumber(&sz)) < 0) || (level >= ply)) {
293         outputf(_("You must specify a valid level 0..%d for the filter "
294                   "(see `help set %s movefilter')"), ply - 1, szSetCommand);
295         return;
296     }
297 
298     pmfFilter = &aamf[ply - 1][level];
299 
300     if ((accept = ParseNumber(&sz)) == INT_MIN) {
301         outputf(N_("You must specify a number of moves to accept (or a negative number to skip "
302                    "this level) (see `help set %s movefilter')"), szSetCommand);
303         return;
304     }
305 
306     if (accept < 0) {
307         pmfFilter->Accept = -1;
308         pmfFilter->Extra = 0;
309         pmfFilter->Threshold = 0.0;
310         return;
311     }
312 
313     if (((extras = ParseNumber(&sz)) < 0) || ((tolerance = ParseReal(&sz)) < 0.0f)) {
314         outputf(_("You must set a count of extra moves and a search tolerance "
315                   "(see `help set %s movefilter')."), szSetCommand);
316         return;
317     }
318 
319     pmfFilter->Accept = accept;
320     pmfFilter->Extra = extras;
321     pmfFilter->Threshold = tolerance;
322 }
323 
324 
325 
326 
327 extern void
CommandSetAnalysisCube(char * sz)328 CommandSetAnalysisCube(char *sz)
329 {
330 
331     if (SetToggle("analysis cube", &fAnalyseCube, sz,
332                   _("Cube action will be analysed."), _("Cube action will not be analysed.")) >= 0)
333         UpdateSetting(&fAnalyseCube);
334 }
335 
336 extern void
CommandSetAnalysisLuck(char * sz)337 CommandSetAnalysisLuck(char *sz)
338 {
339 
340     if (SetToggle("analysis luck", &fAnalyseDice, sz,
341                   _("Dice rolls will be analysed."), _("Dice rolls will not be analysed.")) >= 0)
342         UpdateSetting(&fAnalyseDice);
343 }
344 
345 extern void
CommandSetAnalysisLuckAnalysis(char * sz)346 CommandSetAnalysisLuckAnalysis(char *sz)
347 {
348 
349 
350     szSet = _("luck analysis");
351     szSetCommand = "set analysis luckanalysis";
352     pecSet = &ecLuck;
353     HandleCommand(sz, acSetEvaluation);
354 
355 }
356 
357 
358 extern void
CommandSetAnalysisMoves(char * sz)359 CommandSetAnalysisMoves(char *sz)
360 {
361 
362     if (SetToggle("analysis moves", &fAnalyseMove, sz,
363                   _("Chequer play will be analysed."), _("Chequer play will not be analysed.")) >= 0)
364         UpdateSetting(&fAnalyseMove);
365 }
366 
367 static void
SetLuckThreshold(lucktype lt,char * sz)368 SetLuckThreshold(lucktype lt, char *sz)
369 {
370 
371     float r = ParseReal(&sz);
372     char *szCommand = gettext(aszLuckTypeCommand[lt]);
373 
374     if (r <= 0.0f) {
375         outputf(_("You must specify a positive number for the threshold (see "
376                   "`help set analysis\nthreshold %s').\n"), szCommand);
377         return;
378     }
379 
380     arLuckLevel[lt] = r;
381 
382     outputf(_("`%s' threshold set to %.3f.\n"), szCommand, r);
383 }
384 
385 static void
SetSkillThreshold(skilltype lt,char * sz)386 SetSkillThreshold(skilltype lt, char *sz)
387 {
388 
389     float r = ParseReal(&sz);
390     char *szCommand = gettext(aszSkillTypeCommand[lt]);
391 
392     if (r < 0.0f) {
393         outputf(_("You must specify a semi-positive number for the threshold (see "
394                   "`help set analysis\nthreshold %s').\n"), szCommand);
395         return;
396     }
397 
398     arSkillLevel[lt] = r;
399 
400     outputf(_("`%s' threshold set to %.3f.\n"), szCommand, r);
401 }
402 
403 extern void
CommandSetAnalysisThresholdBad(char * sz)404 CommandSetAnalysisThresholdBad(char *sz)
405 {
406 
407     SetSkillThreshold(SKILL_BAD, sz);
408 }
409 
410 extern void
CommandSetAnalysisThresholdDoubtful(char * sz)411 CommandSetAnalysisThresholdDoubtful(char *sz)
412 {
413 
414     SetSkillThreshold(SKILL_DOUBTFUL, sz);
415 }
416 
417 extern void
CommandSetAnalysisThresholdLucky(char * sz)418 CommandSetAnalysisThresholdLucky(char *sz)
419 {
420 
421     SetLuckThreshold(LUCK_GOOD, sz);
422 }
423 
424 extern void
CommandSetAnalysisThresholdUnlucky(char * sz)425 CommandSetAnalysisThresholdUnlucky(char *sz)
426 {
427 
428     SetLuckThreshold(LUCK_BAD, sz);
429 }
430 
431 extern void
CommandSetAnalysisThresholdVeryBad(char * sz)432 CommandSetAnalysisThresholdVeryBad(char *sz)
433 {
434 
435     SetSkillThreshold(SKILL_VERYBAD, sz);
436 }
437 
438 extern void
CommandSetAnalysisThresholdVeryLucky(char * sz)439 CommandSetAnalysisThresholdVeryLucky(char *sz)
440 {
441 
442     SetLuckThreshold(LUCK_VERYGOOD, sz);
443 }
444 
445 extern void
CommandSetAnalysisThresholdVeryUnlucky(char * sz)446 CommandSetAnalysisThresholdVeryUnlucky(char *sz)
447 {
448 
449     SetLuckThreshold(LUCK_VERYBAD, sz);
450 }
451 
452 extern void
CommandSetStyledGameList(char * sz)453 CommandSetStyledGameList(char *sz)
454 {
455 
456     SetToggle("styledgamelist", &fStyledGamelist, sz,
457               _("Show colours in game window"), _("Do not show colours in game window."));
458 
459 #if defined(USE_GTK)
460     if (fX)
461         ChangeGame(NULL);
462 #endif
463 }
464 
465 extern void
CommandSetFullScreen(char * sz)466 CommandSetFullScreen(char *sz)
467 {
468     int newValue = fFullScreen;
469     SetToggle("fullscreen", &newValue, sz, _("Show board in full screen mode"), _("Show board in normal screen mode."));
470 
471     if (newValue != fFullScreen) {      /* Value has changed */
472         fFullScreen = newValue;
473 #if defined(USE_GTK)
474         if (fX)
475             FullScreenMode(fFullScreen);
476 #endif
477     }
478 }
479 
480 extern void
CommandSetAutoBearoff(char * sz)481 CommandSetAutoBearoff(char *sz)
482 {
483 
484     SetToggle("automatic bearoff", &fAutoBearoff, sz, _("Will automatically "
485                                                         "bear off as many chequers as possible."), _("Will not "
486                                                                                                      "automatically bear off chequers."));
487 }
488 
489 extern void
CommandSetAutoCrawford(char * sz)490 CommandSetAutoCrawford(char *sz)
491 {
492 
493     SetToggle("automatic crawford", &fAutoCrawford, sz, _("Will enable the "
494                                                           "Crawford game according to match score."), _("Will not "
495                                                                                                         "enable the Crawford game according to match score."));
496 }
497 
498 extern void
CommandSetAutoDoubles(char * sz)499 CommandSetAutoDoubles(char *sz)
500 {
501 
502     int n;
503 
504     if ((n = ParseNumber(&sz)) < 0) {
505         outputl(_("You must specify how many automatic doubles to use " "(see `help set automatic double')."));
506         return;
507     }
508 
509     if (n > 12) {
510         outputl(_("Please specify a smaller limit (up to 12 automatic " "doubles)."));
511         return;
512     }
513 
514     if ((cAutoDoubles = (unsigned int) n) > 1)
515         outputf(_("Automatic doubles will be used " "(up to a limit of %d).\n"), n);
516     else if (cAutoDoubles)
517         outputl(_("A single automatic double will be permitted."));
518     else
519         outputl(_("Automatic doubles will not be used."));
520 
521     UpdateSetting(&cAutoDoubles);
522 
523     if (cAutoDoubles) {
524         if (ms.nMatchTo > 0)
525             outputl(_("(Note that automatic doubles will have " "no effect until you " "start session play.)"));
526         else if (!ms.fCubeUse)
527             outputl(_("Note that automatic doubles will have no effect "
528                       "until you " "enable cube use\n(see `help set cube use')."));
529     }
530 }
531 
532 extern void
CommandSetAutoGame(char * sz)533 CommandSetAutoGame(char *sz)
534 {
535 
536     SetToggle("automatic game", &fAutoGame, sz,
537               _("Will automatically start games after wins."), _("Will not automatically start games."));
538 }
539 
540 extern void
CommandSetAutoMove(char * sz)541 CommandSetAutoMove(char *sz)
542 {
543 
544     SetToggle("automatic move", &fAutoMove, sz,
545               _("Forced moves will be made automatically."), _("Forced moves will not be made automatically."));
546 }
547 
548 extern void
CommandSetAutoRoll(char * sz)549 CommandSetAutoRoll(char *sz)
550 {
551 
552     SetToggle("automatic roll", &fAutoRoll, sz,
553               _("Will automatically roll the "
554                 "dice when no cube action is possible."), _("Will not automatically roll the dice."));
555 }
556 
557 static int
CorrectNumberOfChequers(TanBoard anBoard,int numCheq)558 CorrectNumberOfChequers(TanBoard anBoard, int numCheq)
559 {                               /* Check players don't have too many chequers (esp. for hypergammon) */
560     int ac[2], i;
561     ac[0] = ac[1] = 0;
562     for (i = 0; i < 25; i++) {
563         ac[0] += anBoard[0][i];
564         ac[1] += anBoard[1][i];
565     }
566     /* Nb. representation doesn't specify how many chequers
567      * may be off the board - so has to be <= not == */
568     if (ac[0] <= numCheq && ac[1] <= numCheq)
569         return 1;
570     else
571         return 0;
572 }
573 
574 extern void
CommandSetBoard(char * sz)575 CommandSetBoard(char *sz)
576 {
577 
578     TanBoard an;
579     moverecord *pmr;
580 
581     if (ms.gs != GAME_PLAYING) {
582         outputl(_("There must be a game in progress to set the board."));
583 
584         return;
585     }
586 
587     if (!*sz) {
588         outputl(_("You must specify a position (see `help set board')."));
589 
590         return;
591     }
592 
593     /* FIXME how should =n notation be handled? */
594     if (ParsePosition(an, &sz, NULL) < 0 || !CorrectNumberOfChequers(an, anChequers[ms.bgv]))
595         return;
596 
597     pmr = NewMoveRecord();
598 
599     pmr->mt = MOVE_SETBOARD;
600     pmr->fPlayer = ms.fMove;
601 
602     if (ms.fMove)
603         SwapSides(an);
604     PositionKey((ConstTanBoard) an, &pmr->sb.key);
605 
606     AddMoveRecord(pmr);
607 
608     /* this way the player turn is stored */
609     get_current_moverecord(NULL);
610 
611     ShowBoard();
612 }
613 
614 static int
CheckCubeAllowed(void)615 CheckCubeAllowed(void)
616 {
617 
618     if (ms.gs != GAME_PLAYING) {
619         outputl(_("There must be a game in progress to set the cube."));
620         return -1;
621     }
622 
623     if (ms.fCrawford) {
624         outputl(_("The cube is disabled during the Crawford game."));
625         return -1;
626     }
627 
628     if (!ms.fCubeUse) {
629         outputl(_("The cube is disabled (see `help set cube use')."));
630         return -1;
631     }
632 
633     return 0;
634 }
635 
636 extern void
CommandSetCache(char * sz)637 CommandSetCache(char *sz)
638 {
639     int n;
640     if ((n = ParseNumber(&sz)) < 0) {
641         outputl(_("You must specify the number of cache entries to use."));
642         return;
643     }
644 
645     n = EvalCacheResize(n);
646     if (n != -1)
647         outputf(ngettext
648                 ("The position cache has been sized to %d entry.\n",
649                  "The position cache has been sized to %d entries.\n", n), n);
650     else
651         outputerr("EvalCacheResize");
652 }
653 
654 #if defined(USE_MULTITHREAD)
655 extern void
CommandSetThreads(char * sz)656 CommandSetThreads(char *sz)
657 {
658     int n;
659 
660     if ((n = ParseNumber(&sz)) <= 0) {
661         outputl(_("You must specify the number of threads to use."));
662 
663         return;
664     }
665 
666     if (n > MAX_NUMTHREADS) {
667         outputf(_("%d is the maximum number of threads supported"), MAX_NUMTHREADS);
668         output(".\n");
669         n = MAX_NUMTHREADS;
670     }
671 
672     MT_SetNumThreads(n);
673     outputf(_("The number of threads has been set to %d.\n"), n);
674 }
675 #endif
676 
677 extern void
CommandSetVsync3d(char * sz)678 CommandSetVsync3d(char *sz)
679 {
680 #if defined(WIN32) && defined(USE_BOARD3D)
681     SetToggle("vsync", &fSync, sz, _("Set vsync on."), _("Set vsync off."));
682     if (setVSync(fSync) == FALSE) {
683         if (gtk_widget_get_realized(pwMain)) {
684             fSync = -1;
685             outputl(_("Unable to set vsync."));
686             return;
687         } else
688             fResetSync = TRUE;  /* Try again once main window is created */
689     }
690     fSync = (fSync != 0) ? 1 : 0;       /* Set to 1 or 0, (-1 == not set) */
691 #else
692     (void) sz;                  /* suppress unused parameter compiler warning */
693     outputl(_("This function is for MS Windows 3D boards only"));
694 #endif
695 }
696 
697 extern void
CommandSetBrowser(char * sz)698 CommandSetBrowser(char *sz)
699 {
700 
701     if (!sz || !*sz)
702         set_web_browser("");
703     set_web_browser(NextToken(&sz));
704 }
705 
706 extern void
CommandSetCalibration(char * sz)707 CommandSetCalibration(char *sz)
708 {
709 
710     float r;
711 
712     if (!sz || !*sz) {
713         rEvalsPerSec = -1.0f;
714         outputl(_("The evaluation speed has been cleared."));
715         return;
716     }
717 
718     if ((r = ParseReal(&sz)) <= 2.0f) {
719         outputl(_("If you give a parameter to `set calibration', it must "
720                   "be a legal number of evaluations per second."));
721         return;
722     }
723 
724     rEvalsPerSec = r;
725 
726     outputf(_("The speed estimate has been set to %.0f static " "evaluations per second.\n"), rEvalsPerSec);
727 }
728 
729 extern void
CommandSetClockwise(char * sz)730 CommandSetClockwise(char *sz)
731 {
732 
733     SetToggle("clockwise", &fClockwise, sz,
734               _("Player 1 moves clockwise (and "
735                 "player 0 moves anticlockwise)."),
736               _("Player 1 moves anticlockwise (and " "player 0 moves clockwise)."));
737 
738 #if defined(USE_GTK)
739     if (fX) {
740 #if defined(USE_BOARD3D)
741         BoardData *bd = BOARD(pwBoard)->board_data;
742         ShowBoard();
743         if (display_is_3d(bd->rd)) {
744             RestrictiveRedraw();
745             RerenderBase(bd->bd3d);
746         }
747 #else
748         ShowBoard();
749 #endif
750     }
751 #endif                          /* USE_GTK */
752 }
753 
754 extern void
CommandSetAppearance(char * sz)755 CommandSetAppearance(char *sz)
756 {
757 #if defined(USE_GTK)
758     SetBoardPreferences(pwBoard, sz);
759 #else
760     char *apch[2];
761 
762     while (ParseKeyValue(&sz, apch))
763         RenderPreferencesParam(GetMainAppearance(), apch[0], apch[1]);
764 #endif
765 }
766 
767 extern void
CommandSetConfirmDefault(char * sz)768 CommandSetConfirmDefault(char *sz)
769 {
770 
771     if (!sz || !*sz) {
772         outputf("Needs an argument!\n");
773         return;
774     }
775     if (strcmp(sz, "yes") == 0)
776         nConfirmDefault = 1;
777     else if (strcmp(sz, "no") == 0)
778         nConfirmDefault = 0;
779     else if (strcmp(sz, "ask") == 0)
780         nConfirmDefault = -1;
781     else
782         outputf(_("Invalid argument\n"));
783 }
784 
785 extern void
CommandSetConfirmNew(char * sz)786 CommandSetConfirmNew(char *sz)
787 {
788 
789     SetToggle("confirm new", &fConfirmNew, sz,
790               _("Will ask for confirmation before "
791                 "aborting games in progress."),
792               _("Will not ask for confirmation " "before aborting games in progress."));
793 }
794 
795 extern void
CommandSetConfirmSave(char * sz)796 CommandSetConfirmSave(char *sz)
797 {
798 
799     SetToggle("confirm save", &fConfirmSave, sz,
800               _("Will ask for confirmation before "
801                 "overwriting existing files."), _("Will not ask for confirmation " "overwriting existing files."));
802 }
803 
804 extern void
CommandSetCubeCentre(char * UNUSED (sz))805 CommandSetCubeCentre(char *UNUSED(sz))
806 {
807 
808     moverecord *pmr;
809 
810     if (CheckCubeAllowed())
811         return;
812 
813     pmr = NewMoveRecord();
814 
815     pmr->mt = MOVE_SETCUBEPOS;
816     pmr->scp.fCubeOwner = -1;
817     pmr->fPlayer = ms.fMove;
818 
819     AddMoveRecord(pmr);
820 
821     outputl(_("The cube has been centred."));
822 
823 #if defined(USE_GTK)
824     if (fX)
825         ShowBoard();
826 #endif                          /* USE_GTK */
827 }
828 
829 extern void
CommandSetCubeOwner(char * sz)830 CommandSetCubeOwner(char *sz)
831 {
832     moverecord *pmr;
833 
834     int i;
835 
836     if (CheckCubeAllowed())
837         return;
838 
839     switch (i = ParsePlayer(NextToken(&sz))) {
840     case 0:
841     case 1:
842         break;
843 
844     case 2:
845         /* "set cube owner both" is the same as "set cube centre" */
846         CommandSetCubeCentre(NULL);
847         return;
848 
849     default:
850         outputl(_("You must specify which player owns the cube " "(see `help set cube owner')."));
851         return;
852     }
853 
854     pmr = NewMoveRecord();
855 
856     pmr->mt = MOVE_SETCUBEPOS;
857     pmr->scp.fCubeOwner = i;
858     pmr->fPlayer = ms.fMove;
859 
860     AddMoveRecord(pmr);
861 
862     outputf(_("%s now owns the cube.\n"), ap[ms.fCubeOwner].szName);
863 
864 #if defined(USE_GTK)
865     if (fX)
866         ShowBoard();
867 #endif                          /* USE_GTK */
868 }
869 
870 extern void
CommandSetCubeUse(char * sz)871 CommandSetCubeUse(char *sz)
872 {
873 
874     if (SetToggle("cube use", &fCubeUse, sz,
875                   _("Use of the doubling cube is permitted."), _("Use of the doubling cube is disabled.")) < 0)
876         return;
877 
878     if (!ms.nMatchTo && ms.fJacoby && !fCubeUse)
879         outputl(_("Note that you'll have to disable the Jacoby rule "
880                   "if you want gammons and\nbackgammons to be scored " "(see `help set jacoby')."));
881 
882     if (ms.fCrawford && fCubeUse)
883         outputl(_("(But the Crawford rule is in effect, " "so you won't be able to use it during\nthis game.)"));
884     else if (ms.gs == GAME_PLAYING && !fCubeUse) {
885         /* The cube was being used and now it isn't; reset it to 1,
886          * centred. */
887         ms.nCube = 1;
888         ms.fCubeOwner = -1;
889         UpdateSetting(&ms.nCube);
890         UpdateSetting(&ms.fCubeOwner);
891         CancelCubeAction();
892     }
893 
894     ms.fCubeUse = fCubeUse;
895 
896 #if defined(USE_GTK)
897     if (fX)
898         ShowBoard();
899 #endif                          /* USE_GTK */
900 }
901 
902 extern void
CommandSetCubeValue(char * sz)903 CommandSetCubeValue(char *sz)
904 {
905 
906     int i, n;
907     moverecord *pmr;
908 
909     if (CheckCubeAllowed())
910         return;
911 
912     n = ParseNumber(&sz);
913 
914     for (i = MAX_CUBE; i; i >>= 1)
915         if (n == i) {
916             pmr = NewMoveRecord();
917             pmr->mt = MOVE_SETCUBEVAL;
918             pmr->fPlayer = ms.fMove;
919 
920             pmr->scv.nCube = n;
921 
922             AddMoveRecord(pmr);
923 
924             outputf(_("The cube has been set to %d.\n"), n);
925 
926 #if defined(USE_GTK)
927             if (fX)
928                 ShowBoard();
929 #endif                          /* USE_GTK */
930             return;
931         }
932 
933     outputl(_("You must specify a legal cube value (see `help set cube " "value')."));
934 }
935 
936 extern void
CommandSetDelay(char * sz)937 CommandSetDelay(char *sz)
938 {
939 #if defined(USE_GTK)
940     if (fX) {
941         int n;
942 
943         if (*sz && !StrNCaseCmp(sz, "none", strlen(sz)))
944             n = 0;
945         else if ((n = ParseNumber(&sz)) < 0 || n > 10000) {
946             outputl(_("You must specify a legal move delay (see `help set " "delay')."));
947             return;
948         }
949 
950         if (n) {
951             outputf(ngettext("All moves will be shown for at least %d millisecond.\n",
952                              "All moves will be shown for at least %d milliseconds.\n", n), n);
953             if (!fDisplay)
954                 outputl(_("You will also need to use `set display' to turn "
955                           "board updates on (see `help set display')."));
956         } else
957             outputl(_("Moves will not be delayed."));
958 
959         nDelay = n;
960         UpdateSetting(&nDelay);
961     } else
962 #endif                          /* USE_GTK */
963         (void) sz;              /* suppress unused parameter compiler warning */
964     outputl(_("The `set delay' command applies only when using a window " "system."));
965 }
966 
967 extern void
CommandSetDice(char * sz)968 CommandSetDice(char *sz)
969 {
970 
971     int n0, n1;
972     moverecord *pmr;
973 
974     if (ms.gs != GAME_PLAYING) {
975         outputl(_("There must be a game in progress to set the dice."));
976 
977         return;
978     }
979 
980     n0 = ParseNumber(&sz);
981 
982     if (n0 > 10) {
983         /* assume a 2-digit number; n0 first digit, n1 second */
984         n1 = n0 % 10;
985         n0 /= 10;
986     } else
987         n1 = ParseNumber(&sz);
988 
989     if (n0 < 1 || n0 > 6 || n1 < 1 || n1 > 6) {
990         outputl(_("You must specify two numbers from 1 to 6 for the dice."));
991 
992         return;
993     }
994 
995     pmr = NewMoveRecord();
996 
997     pmr->mt = MOVE_SETDICE;
998     pmr->fPlayer = ms.fMove;
999     pmr->anDice[0] = n0;
1000     pmr->anDice[1] = n1;
1001 
1002     AddMoveRecord(pmr);
1003 
1004     outputf(_("The dice have been set to %d and %d.\n"), n0, n1);
1005 
1006 #if defined(USE_BOARD3D)
1007     RestrictiveRedraw();
1008 #endif
1009 #if defined(USE_GTK)
1010     if (fX)
1011         ShowBoard();
1012 #endif
1013 }
1014 
1015 extern void
CommandSetDisplay(char * sz)1016 CommandSetDisplay(char *sz)
1017 {
1018 
1019     SetToggle("display", &fDisplay, sz, _("Will display boards for computer "
1020                                           "moves."), _("Will not display boards for computer moves."));
1021 }
1022 
1023 extern void
CommandSetEvalCubeful(char * sz)1024 CommandSetEvalCubeful(char *sz)
1025 {
1026 
1027     char asz[2][128], szCommand[64];
1028     int f = pecSet->fCubeful;
1029 
1030     sprintf(asz[0], _("%s will use cubeful evaluation.\n"), szSet);
1031     sprintf(asz[1], _("%s will use cubeless evaluation.\n"), szSet);
1032     sprintf(szCommand, "%s cubeful", szSetCommand);
1033     SetToggle(szCommand, &f, sz, asz[0], asz[1]);
1034     pecSet->fCubeful = f;
1035 }
1036 
1037 extern void
CommandSetEvalPrune(char * sz)1038 CommandSetEvalPrune(char *sz)
1039 {
1040 
1041     char asz[2][128], szCommand[64];
1042     int f = pecSet->fUsePrune;
1043 
1044     sprintf(asz[0], _("%s will use pruning.\n"), szSet);
1045     sprintf(asz[1], _("%s will not use pruning.\n"), szSet);
1046     sprintf(szCommand, "%s prune", szSetCommand);
1047     SetToggle(szCommand, &f, sz, asz[0], asz[1]);
1048     pecSet->fUsePrune = f;
1049 }
1050 
1051 extern void
CommandSetEvalDeterministic(char * sz)1052 CommandSetEvalDeterministic(char *sz)
1053 {
1054 
1055     char asz[2][128], szCommand[64];
1056     int f = pecSet->fDeterministic;
1057 
1058     sprintf(asz[0], _("%s will use deterministic noise.\n"), szSet);
1059     sprintf(asz[1], _("%s will use pseudo-random noise.\n"), szSet);
1060     sprintf(szCommand, "%s deterministic", szSetCommand);
1061     SetToggle(szCommand, &f, sz, asz[0], asz[1]);
1062     pecSet->fDeterministic = f;
1063 
1064     if (pecSet->rNoise == 0.0f)
1065         outputl(_("(Note that this setting will have no effect unless you " "set noise to some non-zero value.)"));
1066 }
1067 
1068 extern void
CommandSetEvalNoise(char * sz)1069 CommandSetEvalNoise(char *sz)
1070 {
1071 
1072     float r = ParseReal(&sz);
1073 
1074     if (r < 0.0f) {
1075         outputf(_("You must specify a valid amount of noise to use " "(see `help set\n%s noise').\n"), szSetCommand);
1076 
1077         return;
1078     }
1079 
1080     pecSet->rNoise = r;
1081 
1082     if (pecSet->rNoise > 0.0f)
1083         outputf(_("%s will use noise with standard deviation %5.3f.\n"), szSet, pecSet->rNoise);
1084     else
1085         outputf(_("%s will use noiseless evaluations.\n"), szSet);
1086 }
1087 
1088 extern void
CommandSetEvalPlies(char * sz)1089 CommandSetEvalPlies(char *sz)
1090 {
1091 
1092     int n = ParseNumber(&sz);
1093 
1094     if (n < 0 || n > 7)
1095         outputf(_("Valid numbers of plies to look ahead are 0 to 7.\n"));
1096     else
1097         pecSet->nPlies = n;
1098 
1099     outputf(_("%s will use %d ply evaluation.\n"), szSet, pecSet->nPlies);
1100 }
1101 
1102 #if defined(USE_GTK)
1103 extern void
CommandSetGUIAnimationBlink(char * UNUSED (sz))1104 CommandSetGUIAnimationBlink(char *UNUSED(sz))
1105 {
1106 
1107     animGUI = ANIMATE_BLINK;
1108 }
1109 
1110 extern void
CommandSetGUIAnimationNone(char * UNUSED (sz))1111 CommandSetGUIAnimationNone(char *UNUSED(sz))
1112 {
1113 
1114     animGUI = ANIMATE_NONE;
1115 }
1116 
1117 extern void
CommandSetGUIAnimationSlide(char * UNUSED (sz))1118 CommandSetGUIAnimationSlide(char *UNUSED(sz))
1119 {
1120 
1121     animGUI = ANIMATE_SLIDE;
1122 }
1123 
1124 extern void
CommandSetGUIAnimationSpeed(char * sz)1125 CommandSetGUIAnimationSpeed(char *sz)
1126 {
1127 
1128     unsigned int n = ParseNumber(&sz);
1129 
1130     if (n > 7) {
1131         outputl(_("You must specify a speed between 0 and 7 " "(see `help set speed')."));
1132 
1133         return;
1134     }
1135 
1136     nGUIAnimSpeed = n;
1137 
1138     outputf(_("Animation speed set to %u.\n"), n);
1139 }
1140 
1141 extern void
CommandSetGUIBeep(char * sz)1142 CommandSetGUIBeep(char *sz)
1143 {
1144 
1145     SetToggle("gui beep", &fGUIBeep, sz,
1146               _("GNU Backgammon will beep on illegal input."), _("GNU Backgammon will not beep on illegal input."));
1147 }
1148 
1149 extern void
CommandSetGUIGrayEdit(char * sz)1150 CommandSetGUIGrayEdit(char *sz)
1151 {
1152 
1153     SetToggle("gui grayedit", &fGUIGrayEdit, sz,
1154               _("Board will be grayed in edit mode."), _("Board will not change color in edit mode."));
1155 }
1156 
1157 
1158 extern void
CommandSetGUIDiceArea(char * sz)1159 CommandSetGUIDiceArea(char *sz)
1160 {
1161 
1162     if (SetToggle("gui dicearea", &GetMainAppearance()->fDiceArea, sz,
1163                   _("A dice icon will be shown below the board when a human "
1164                     "player is on roll."), _("No dice icon will be shown.")) >= 0)
1165         UpdateSetting(&GetMainAppearance()->fDiceArea);
1166 }
1167 
1168 extern void
CommandSetGUIHighDieFirst(char * sz)1169 CommandSetGUIHighDieFirst(char *sz)
1170 {
1171 
1172     SetToggle("gui highdiefirst", &fGUIHighDieFirst, sz,
1173               _("The higher die will be shown on the left."), _("The dice will be shown in the order rolled."));
1174 }
1175 
1176 extern void
CommandSetGUIIllegal(char * sz)1177 CommandSetGUIIllegal(char *sz)
1178 {
1179 
1180     SetToggle("gui illegal", &fGUIIllegal, sz,
1181               _("Chequers may be dragged to illegal points."), _("Chequers may not be dragged to illegal points."));
1182 }
1183 
1184 extern void
CommandSetGUIShowIDs(char * sz)1185 CommandSetGUIShowIDs(char *sz)
1186 {
1187     if (!inCallback) {
1188         SetToggle("gui showids", &fShowIDs, sz,
1189                   _("The position and match IDs will be shown above the board."),
1190                   _("The position and match IDs will not be shown."));
1191     }
1192 }
1193 
1194 extern void
CommandSetGUIDragTargetHelp(char * sz)1195 CommandSetGUIDragTargetHelp(char *sz)
1196 {
1197 
1198     if (SetToggle("gui dragtargethelp", &fGUIDragTargetHelp, sz,
1199                   _("The target help while dragging a chequer will "
1200                     "be shown."), _("The target help while dragging a chequer will " "not be shown.")))
1201         UpdateSetting(&fGUIDragTargetHelp);
1202 }
1203 
1204 extern void
CommandSetGUIUseStatsPanel(char * sz)1205 CommandSetGUIUseStatsPanel(char *sz)
1206 {
1207 
1208     SetToggle("gui usestatspanel", &fGUIUseStatsPanel, sz,
1209               _("The match statistics will be shown in a panel"), _("The match statistics will be shown in a list"));
1210 }
1211 
1212 extern void
CommandSetGUIMoveListDetail(char * sz)1213 CommandSetGUIMoveListDetail(char *sz)
1214 {
1215     SetToggle("gui movelistdetail", &showMoveListDetail, sz,
1216               _("The win loss statistics will be shown in the move analysis"),
1217               _("Basic details will be shown in the move analysis"));
1218 }
1219 
1220 extern void
CommandSetGUIShowPipsNone(char * UNUSED (sz))1221 CommandSetGUIShowPipsNone(char *UNUSED(sz))
1222 {
1223     gui_show_pips = GUI_SHOW_PIPS_NONE;
1224     outputf(_("The pip counts will not be shown."));
1225     UpdateSetting(&gui_show_pips);
1226 }
1227 
1228 extern void
CommandSetGUIShowPipsPips(char * UNUSED (sz))1229 CommandSetGUIShowPipsPips(char *UNUSED(sz))
1230 {
1231     gui_show_pips = GUI_SHOW_PIPS_PIPS;
1232     outputf(_("Pip counts will be shown."));
1233     UpdateSetting(&gui_show_pips);
1234 }
1235 
1236 extern void
CommandSetGUIShowPipsEPC(char * UNUSED (sz))1237 CommandSetGUIShowPipsEPC(char *UNUSED(sz))
1238 {
1239     gui_show_pips = GUI_SHOW_PIPS_EPC;
1240     outputf(_("Effective pip counts will be shown."));
1241     UpdateSetting(&gui_show_pips);
1242 }
1243 
1244 extern void
CommandSetGUIShowPipsWastage(char * UNUSED (sz))1245 CommandSetGUIShowPipsWastage(char *UNUSED(sz))
1246 {
1247     gui_show_pips = GUI_SHOW_PIPS_WASTAGE;
1248     outputf(_("Pip wastage will be shown."));
1249     UpdateSetting(&gui_show_pips);
1250 }
1251 
1252 extern void
CommandSetGUIWindowPositions(char * sz)1253 CommandSetGUIWindowPositions(char *sz)
1254 {
1255 
1256     SetToggle("gui windowpositions", &fGUISetWindowPos, sz,
1257               _("Saved window positions will be applied to new windows."),
1258               _("Saved window positions will not be applied to new " "windows."));
1259 }
1260 #else
1261 static void
NoGUI(void)1262 NoGUI(void)
1263 {
1264 
1265     outputl(_("This installation of GNU Backgammon was compiled without GUI " "support."));
1266 }
1267 
1268 extern void
CommandSetGUIAnimationBlink(char * UNUSED (sz))1269 CommandSetGUIAnimationBlink(char *UNUSED(sz))
1270 {
1271 
1272     NoGUI();
1273 }
1274 
1275 extern void
CommandSetGUIAnimationNone(char * UNUSED (sz))1276 CommandSetGUIAnimationNone(char *UNUSED(sz))
1277 {
1278 
1279     NoGUI();
1280 }
1281 
1282 extern void
CommandSetGUIAnimationSlide(char * UNUSED (sz))1283 CommandSetGUIAnimationSlide(char *UNUSED(sz))
1284 {
1285 
1286     NoGUI();
1287 }
1288 
1289 extern void
CommandSetGUIAnimationSpeed(char * UNUSED (sz))1290 CommandSetGUIAnimationSpeed(char *UNUSED(sz))
1291 {
1292 
1293     NoGUI();
1294 }
1295 
1296 extern void
CommandSetGUIBeep(char * UNUSED (sz))1297 CommandSetGUIBeep(char *UNUSED(sz))
1298 {
1299 
1300     NoGUI();
1301 }
1302 
1303 extern void
CommandSetGUIDiceArea(char * UNUSED (sz))1304 CommandSetGUIDiceArea(char *UNUSED(sz))
1305 {
1306 
1307     NoGUI();
1308 }
1309 
1310 extern void
CommandSetGUIHighDieFirst(char * UNUSED (sz))1311 CommandSetGUIHighDieFirst(char *UNUSED(sz))
1312 {
1313 
1314     NoGUI();
1315 }
1316 
1317 extern void
CommandSetGUIIllegal(char * UNUSED (sz))1318 CommandSetGUIIllegal(char *UNUSED(sz))
1319 {
1320 
1321     NoGUI();
1322 }
1323 
1324 extern void
CommandSetGUIShowIDs(char * UNUSED (sz))1325 CommandSetGUIShowIDs(char *UNUSED(sz))
1326 {
1327 
1328     NoGUI();
1329 }
1330 
1331 extern void
CommandSetGUIShowPipsNone(char * UNUSED (sz))1332 CommandSetGUIShowPipsNone(char *UNUSED(sz))
1333 {
1334     NoGUI();
1335 }
1336 
1337 extern void
CommandSetGUIShowPipsPips(char * UNUSED (sz))1338 CommandSetGUIShowPipsPips(char *UNUSED(sz))
1339 {
1340     NoGUI();
1341 }
1342 
1343 extern void
CommandSetGUIShowPipsEPC(char * UNUSED (sz))1344 CommandSetGUIShowPipsEPC(char *UNUSED(sz))
1345 {
1346     NoGUI();
1347 }
1348 
1349 extern void
CommandSetGUIShowPipsWastage(char * UNUSED (sz))1350 CommandSetGUIShowPipsWastage(char *UNUSED(sz))
1351 {
1352     NoGUI();
1353 }
1354 
1355 extern void
CommandSetGUIWindowPositions(char * UNUSED (sz))1356 CommandSetGUIWindowPositions(char *UNUSED(sz))
1357 {
1358 
1359     NoGUI();
1360 }
1361 #endif
1362 
1363 extern void
CommandSetPlayerMoveFilter(char * sz)1364 CommandSetPlayerMoveFilter(char *sz)
1365 {
1366 
1367     SetMoveFilter(sz, ap[iPlayerSet].aamf);
1368 
1369 }
1370 
1371 extern void
CommandSetPlayerChequerplay(char * sz)1372 CommandSetPlayerChequerplay(char *sz)
1373 {
1374 
1375     szSet = ap[iPlayerSet].szName;
1376     szSetCommand = "player chequerplay evaluation";
1377     pesSet = &ap[iPlayerSet].esChequer;
1378 
1379     outputpostpone();
1380 
1381     HandleCommand(sz, acSetEvalParam);
1382 
1383     if (ap[iPlayerSet].pt != PLAYER_GNU)
1384         outputf(_("(Note that this setting will have no effect until you "
1385                   "`set player %s gnu'.)\n"), ap[iPlayerSet].szName);
1386 
1387     outputresume();
1388 }
1389 
1390 
1391 extern void
CommandSetPlayerCubedecision(char * sz)1392 CommandSetPlayerCubedecision(char *sz)
1393 {
1394 
1395     szSet = ap[iPlayerSet].szName;
1396     szSetCommand = "player cubedecision evaluation";
1397     pesSet = &ap[iPlayerSet].esCube;
1398 
1399     outputpostpone();
1400 
1401     HandleCommand(sz, acSetEvalParam);
1402 
1403     if (ap[iPlayerSet].pt != PLAYER_GNU)
1404         outputf(_("(Note that this setting will have no effect until you "
1405                   "`set player %s gnu'.)\n"), ap[iPlayerSet].szName);
1406 
1407     outputresume();
1408 }
1409 
1410 
1411 extern void
CommandSetPlayerExternal(char * sz)1412 CommandSetPlayerExternal(char *sz)
1413 {
1414 
1415 #if !defined(HAVE_SOCKETS)
1416     (void) sz;                  /* suppress unused parameter compiler warning */
1417     outputl(_("This installation of GNU Backgammon was compiled without\n"
1418               "socket support, and does not implement external players."));
1419 #else
1420     int h, cb;
1421     struct sockaddr *psa;
1422     char *pch;
1423 
1424     if (ap[iPlayerSet].pt == PLAYER_EXTERNAL)
1425         closesocket(ap[iPlayerSet].h);
1426 
1427     sz = NextToken(&sz);
1428 
1429     if (!sz || !*sz) {
1430         outputl(_("You must specify the name of the socket to the external\n"
1431                   "player (see `help set player external')."));
1432         return;
1433     }
1434 
1435     pch = strcpy(malloc(strlen(sz) + 1), sz);
1436 
1437     if ((h = ExternalSocket(&psa, &cb, sz)) < 0) {
1438         SockErr(pch);
1439         free(pch);
1440         return;
1441     }
1442 
1443     while (connect(h, psa, cb) < 0) {
1444         if (errno == EINTR) {
1445             if (fInterrupt) {
1446                 closesocket(h);
1447                 free(psa);
1448                 free(pch);
1449                 return;
1450             }
1451             continue;
1452         }
1453 
1454         SockErr(pch);
1455         closesocket(h);
1456         free(psa);
1457         free(pch);
1458         return;
1459     }
1460 
1461     ap[iPlayerSet].pt = PLAYER_EXTERNAL;
1462     ap[iPlayerSet].h = h;
1463     if (ap[iPlayerSet].szSocket)
1464         free(ap[iPlayerSet].szSocket);
1465     ap[iPlayerSet].szSocket = pch;
1466 
1467     free(psa);
1468 #endif                          /* !HAVE_SOCKETS */
1469 }
1470 
1471 extern void
CommandSetPlayerGNU(char * UNUSED (sz))1472 CommandSetPlayerGNU(char *UNUSED(sz))
1473 {
1474 
1475 #if defined(HAVE_SOCKETS)
1476     if (ap[iPlayerSet].pt == PLAYER_EXTERNAL)
1477         closesocket(ap[iPlayerSet].h);
1478 #endif
1479 
1480     ap[iPlayerSet].pt = PLAYER_GNU;
1481 
1482     outputf(_("Moves for %s will now be played by GNU Backgammon.\n"), ap[iPlayerSet].szName);
1483 
1484 #if defined(USE_GTK)
1485     if (fX)
1486         /* The "play" button might now be required; update the board. */
1487         ShowBoard();
1488 #endif                          /* USE_GTK */
1489 }
1490 
1491 extern void
CommandSetPlayerHuman(char * UNUSED (sz))1492 CommandSetPlayerHuman(char *UNUSED(sz))
1493 {
1494 
1495 #if defined(HAVE_SOCKETS)
1496     if (ap[iPlayerSet].pt == PLAYER_EXTERNAL)
1497         closesocket(ap[iPlayerSet].h);
1498 #endif
1499 
1500     ap[iPlayerSet].pt = PLAYER_HUMAN;
1501 
1502     outputf(_("Moves for %s must now be entered manually.\n"), ap[iPlayerSet].szName);
1503 }
1504 
1505 extern void
CommandSetPlayerName(char * sz)1506 CommandSetPlayerName(char *sz)
1507 {
1508 
1509     if (!sz || !*sz) {
1510         outputl(_("You must specify a name to use."));
1511 
1512         return;
1513     }
1514 
1515     if (strlen(sz) > 31)
1516         sz[31] = 0;
1517 
1518     if ((*sz == '0' || *sz == '1') && !sz[1]) {
1519         outputf(_("`%c' is not a valid name.\n"), *sz);
1520 
1521         return;
1522     }
1523 
1524     if (!StrCaseCmp(sz, "both")) {
1525         outputl(_("`both' is a reserved word; you can't call a player " "that.\n"));
1526 
1527         return;
1528     }
1529 
1530     if (!CompareNames(sz, ap[!iPlayerSet].szName)) {
1531         outputl(_("That name is already in use by the other player."));
1532 
1533         return;
1534     }
1535 
1536     strcpy(ap[iPlayerSet].szName, sz);
1537 
1538     outputf(_("Player %d is now known as `%s'.\n"), iPlayerSet, sz);
1539 
1540 #if defined(USE_GTK)
1541     if (fX)
1542         ShowBoard();
1543 #endif                          /* USE_GTK */
1544 }
1545 
1546 extern void
CommandSetPlayer(char * sz)1547 CommandSetPlayer(char *sz)
1548 {
1549 
1550     char *pch = NextToken(&sz), *pchCopy;
1551     int i;
1552     char szTemp[32];
1553 
1554     if (!pch) {
1555         outputl(_("You must specify a player (see `help set player')."));
1556 
1557         return;
1558     }
1559 
1560     szSetCommand = szTemp;
1561 
1562     if ((i = ParsePlayer(pch)) == 0 || i == 1) {
1563         iPlayerSet = i;
1564         sprintf(szTemp, "player %d", i);
1565 
1566         HandleCommand(sz, acSetPlayer);
1567         UpdateSetting(ap);
1568 
1569         szSetCommand = NULL;
1570         return;
1571     }
1572 
1573     if (i == 2) {
1574         if ((pchCopy = malloc(strlen(sz) + 1)) == 0) {
1575             outputl(_("Insufficient memory."));
1576 
1577             szSetCommand = NULL;
1578             return;
1579         }
1580 
1581         strcpy(pchCopy, sz);
1582 
1583         outputpostpone();
1584 
1585         iPlayerSet = 0;
1586         szSetCommand = "player 0";
1587         HandleCommand(sz, acSetPlayer);
1588 
1589         iPlayerSet = 1;
1590         szSetCommand = "player 1";
1591         HandleCommand(pchCopy, acSetPlayer);
1592 
1593         outputresume();
1594 
1595         UpdateSetting(ap);
1596 
1597         free(pchCopy);
1598 
1599         szSetCommand = NULL;
1600         return;
1601     }
1602 
1603     outputf(_("Unknown player `%s' (see `help set player').\n"), pch);
1604 
1605     szSetCommand = NULL;
1606     return;
1607 }
1608 
1609 
1610 extern void
CommandSetDefaultNames(char * sz)1611 CommandSetDefaultNames(char *sz)
1612 {
1613     char *names[2] = { NextToken(&sz), NextToken(&sz) };
1614     int i;
1615 
1616     for (i = 0; i < 2; i++) {
1617         char *pch = names[i];
1618         if (!pch || !*pch) {
1619             outputl(_("You must specify two player names."));
1620             return;
1621         }
1622 
1623         if (strlen(pch) > 31)
1624             pch[31] = 0;
1625 
1626         if ((*pch == '0' || *pch == '1') && !pch[1]) {
1627             outputf(_("`%c' is not a valid name.\n"), *pch);
1628             return;
1629         }
1630 
1631         if (!StrCaseCmp(pch, "both")) {
1632             outputl(_("`both' is a reserved word; you can't call a player " "that.\n"));
1633             return;
1634         }
1635     }
1636 
1637     if (!CompareNames(names[0], names[1])) {
1638         outputl(_("Player names identical"));
1639         return;
1640     }
1641     if (StrCaseCmp(names[0], default_names[0]) == 0 && StrCaseCmp(names[1], default_names[1]) == 0)
1642         return;
1643 
1644     strcpy(default_names[0], names[0]);
1645     strcpy(default_names[1], names[1]);
1646 
1647     outputf(_("Players will be known as `%s' and `%s'.\n This setting will take effect when a new match is started.\n"),
1648             default_names[0], default_names[1]);
1649 }
1650 
1651 extern void
CommandSetAliases(char * sz)1652 CommandSetAliases(char *sz)
1653 {
1654     if (strlen(sz) >= sizeof(player1aliases))
1655         outputf("%s %lu %s.\n", _("Aliases list limited to"), (long unsigned int) (sizeof(player1aliases) - 1),
1656                 _("characters, truncating"));
1657 
1658     strncpy(player1aliases, sz, sizeof(player1aliases) - 1);
1659 
1660     outputf(_("Aliases for player 1 when importing MAT files set to \"%s\".\n "), player1aliases);
1661 }
1662 
1663 
1664 extern void
CommandSetPrompt(char * szParam)1665 CommandSetPrompt(char *szParam)
1666 {
1667     static char sz[128];        /* FIXME check overflow */
1668 
1669     szPrompt = (szParam && *szParam) ? strcpy(sz, szParam) : szDefaultPrompt;
1670 
1671     outputf(_("The prompt has been set to `%s'.\n"), szPrompt);
1672 }
1673 
1674 extern void
CommandSetRecord(char * sz)1675 CommandSetRecord(char *sz)
1676 {
1677     SetToggle("record", &fRecord, sz,
1678               _("All games in a session will be recorded."), _("Only the active game in a session will be recorded."));
1679 }
1680 
1681 extern void
CommandSetRNG(char * sz)1682 CommandSetRNG(char *sz)
1683 {
1684     rngSet = &rngCurrent;
1685     rngctxSet = rngctxCurrent;
1686     HandleCommand(sz, acSetRNG);
1687 }
1688 
1689 extern void
CommandSetRNGFile(char * sz)1690 CommandSetRNGFile(char *sz)
1691 {
1692     SetRNG(rngSet, rngctxSet, RNG_FILE, sz);
1693 }
1694 
1695 #if defined(HAVE_LIBGMP)
1696 extern void
CommandSetRNGBBS(char * sz)1697 CommandSetRNGBBS(char *sz)
1698 {
1699     SetRNG(rngSet, rngctxSet, RNG_BBS, sz);
1700 #else
1701 extern void
1702 CommandSetRNGBBS(char *UNUSED(sz))
1703 {
1704     outputl(_("This installation of GNU Backgammon was compiled without the " "Blum, Blum and Shub generator."));
1705 #endif                          /* HAVE_LIBGMP */
1706 }
1707 
1708 extern void
1709 CommandSetRNGIsaac(char *sz)
1710 {
1711     SetRNG(rngSet, rngctxSet, RNG_ISAAC, sz);
1712 }
1713 
1714 extern void
1715 CommandSetRNGManual(char *sz)
1716 {
1717     SetRNG(rngSet, rngctxSet, RNG_MANUAL, sz);
1718 }
1719 
1720 extern void
1721 CommandSetRNGMD5(char *sz)
1722 {
1723     SetRNG(rngSet, rngctxSet, RNG_MD5, sz);
1724 }
1725 
1726 extern void
1727 CommandSetRNGMersenne(char *sz)
1728 {
1729     SetRNG(rngSet, rngctxSet, RNG_MERSENNE, sz);
1730 }
1731 
1732 extern void
1733 CommandSetRNGRandomDotOrg(char *sz)
1734 {
1735 
1736 #if defined(LIBCURL_PROTOCOL_HTTPS)
1737     SetRNG(rngSet, rngctxSet, RNG_RANDOM_DOT_ORG, sz);
1738 #else
1739     (void) sz;                  /* suppress unused parameter compiler warning */
1740     outputl(_("This installation of GNU Backgammon was compiled without\n"
1741               "support for HTTPS(libcurl) which is needed for fetching\n" "random numbers from <www.random.org>"));
1742 #endif
1743 
1744 }
1745 
1746 extern void
1747 CommandSetRolloutLate(char *sz)
1748 {
1749 
1750     HandleCommand(sz, acSetRolloutLate);
1751 
1752 }
1753 
1754 extern void
1755 CommandSetRolloutLogEnable(char *sz)
1756 {
1757     int f = log_rollouts;
1758 
1759     SetToggle("rollout .sgf files", &f, sz,
1760               _("Create an .sgf file for each game rolled out"),
1761               _("Do not create an .sgf file for each game rolled out"));
1762 
1763     log_rollouts = f;
1764 }
1765 
1766 extern void
1767 CommandSetRolloutLogFile(char *sz)
1768 {
1769 
1770     if (log_file_name) {
1771         free(log_file_name);
1772     }
1773 
1774     log_file_name = g_strdup(sz);
1775 }
1776 
1777 extern void
1778 CommandSetRolloutLateEnable(char *sz)
1779 {
1780     int l = prcSet->fLateEvals;
1781     if (SetToggle("separate evaluation for later plies", &l, sz,
1782                   _("Use different evaluation for later moves of rollout."),
1783                   _("Do not change evaluations during rollout.")) != -1) {
1784         prcSet->fLateEvals = l;
1785     }
1786 }
1787 
1788 extern void
1789 CommandSetRolloutLatePlies(char *sz)
1790 {
1791 
1792     int n = ParseNumber(&sz);
1793 
1794     if (n < 1) {
1795         outputl(_("You must specify a valid ply at which to change evaluations "
1796                   "(see `help set rollout late plies')."));
1797 
1798         return;
1799     }
1800 
1801     prcSet->nLate = (unsigned short) n;
1802 
1803     if (!n)
1804         outputl(_("No evaluations changes will be made during rollouts."));
1805     else
1806         outputf(_("Evaluations will change after %d plies in rollouts.\n"), n);
1807 
1808 }
1809 
1810 
1811 extern void
1812 CommandSetRolloutTruncation(char *sz)
1813 {
1814 
1815     HandleCommand(sz, acSetTruncation);
1816 }
1817 
1818 extern void
1819 CommandSetRolloutLimit(char *sz)
1820 {
1821 
1822     HandleCommand(sz, acSetRolloutLimit);
1823 
1824 }
1825 
1826 extern void
1827 CommandSetRolloutLimitEnable(char *sz)
1828 {
1829     int s = prcSet->fStopOnSTD;
1830 
1831     if (SetToggle("stop when the STD's are small enough", &s, sz,
1832                   _("Stop rollout when STD's are small enough"), _("Do not stop rollout based on STDs")) != -1) {
1833         prcSet->fStopOnSTD = s;
1834     }
1835 }
1836 
1837 extern void
1838 CommandSetRolloutLimitMinGames(char *sz)
1839 {
1840 
1841     int n = ParseNumber(&sz);
1842 
1843     if (n < 1) {
1844         outputl(_("You must specify a valid minimum number of games to rollout "
1845                   "(see `help set rollout limit minimumgames')."));
1846         return;
1847     }
1848 
1849     prcSet->nMinimumGames = n;
1850 
1851     outputf(_("After %d games, rollouts will stop if the STDs are small enough" ".\n"), n);
1852 }
1853 
1854 extern void
1855 CommandSetRolloutMaxError(char *sz)
1856 {
1857 
1858     float r = ParseReal(&sz);
1859 
1860     if (r < 0.0001f) {
1861         outputl(_("You must set a valid STD where rollouts can stop " "(see `help set rollout limit maxerror')."));
1862         return;
1863     }
1864 
1865     prcSet->rStdLimit = r;
1866 
1867     outputf(_("Rollouts can stop when the estimated equities' STD are less than " "%5.4f)\n"), r);
1868 }
1869 
1870 extern void
1871 CommandSetRolloutJsd(char *sz)
1872 {
1873 
1874     HandleCommand(sz, acSetRolloutJsd);
1875 
1876 }
1877 
1878 extern void
1879 CommandSetRolloutJsdEnable(char *sz)
1880 {
1881     int s = prcSet->fStopOnJsd;
1882     if (SetToggle("stop rollout of choices which appear to  "
1883                   "to be worse with statistical certainty", &s, sz,
1884                   _("Stop rollout of choices based on JSDs"),
1885                   _("Do not stop rollout of moves choices on JSDs")) != -1) {
1886         prcSet->fStopOnJsd = s;
1887     }
1888 }
1889 
1890 extern void
1891 CommandSetRolloutJsdMinGames(char *sz)
1892 {
1893 
1894     int n = ParseNumber(&sz);
1895 
1896     if (n < 1) {
1897         outputl(_("You must specify a valid minimum number of games to rollout "
1898                   "(see `help set rollout jsd minimumgames')."));
1899         return;
1900     }
1901     prcSet->nMinimumJsdGames = n;
1902 
1903     outputf(_("After %d games, rollouts will stop if the JSDs are large enough" ".\n"), n);
1904 }
1905 
1906 
1907 extern void
1908 CommandSetRolloutJsdLimit(char *sz)
1909 {
1910 
1911     float r = ParseReal(&sz);
1912 
1913     if (r < 0.0001f) {
1914         outputl(_("You must set a number of joint standard deviations for the equity"
1915                   " difference with the best move being rolled out " "(see `help set rollout jsd limit')."));
1916         return;
1917     }
1918 
1919     prcSet->rJsdLimit = r;
1920 
1921     outputf(_("Rollouts (or rollouts of moves) may stop when the equity is more "
1922               "than %5.3f joint standard deviations from the best move being rolled out\n"), r);
1923 }
1924 
1925 extern void
1926 CommandSetRollout(char *sz)
1927 {
1928 
1929     prcSet = &rcRollout;
1930     HandleCommand(sz, acSetRollout);
1931 
1932 }
1933 
1934 
1935 extern void
1936 CommandSetRolloutRNG(char *sz)
1937 {
1938 
1939     rngSet = &prcSet->rngRollout;
1940     rngctxSet = rngctxRollout;
1941     HandleCommand(sz, acSetRNG);
1942 
1943 }
1944 
1945 /* set an eval context, then copy to other player's settings */
1946 static void
1947 SetRolloutEvaluationContextBoth(char *sz, evalcontext * pec[])
1948 {
1949 
1950     g_assert(pec[0] != 0);
1951     g_assert(pec[1] != 0);
1952 
1953     pecSet = pec[0];
1954 
1955     HandleCommand(sz, acSetEvaluation);
1956 
1957     /* copy to both players */
1958     /* FIXME don't copy if there was an error setting player 0 */
1959     memcpy(pec[1], pec[0], sizeof(evalcontext));
1960 
1961 }
1962 
1963 extern void
1964 CommandSetRolloutChequerplay(char *sz)
1965 {
1966 
1967     evalcontext *pec[2];
1968 
1969     szSet = _("Chequer play in rollouts");
1970     szSetCommand = "rollout chequerplay";
1971 
1972     pec[0] = prcSet->aecChequer;
1973     pec[1] = prcSet->aecChequer + 1;
1974 
1975     SetRolloutEvaluationContextBoth(sz, pec);
1976 
1977 }
1978 
1979 extern void
1980 CommandSetRolloutMoveFilter(char *sz)
1981 {
1982 
1983     szSetCommand = "rollout";
1984     SetMoveFilter(sz, prcSet->aaamfChequer[0]);
1985     SetMoveFilter(sz, prcSet->aaamfChequer[1]);
1986 
1987 }
1988 
1989 extern void
1990 CommandSetRolloutLateMoveFilter(char *sz)
1991 {
1992 
1993     szSetCommand = "rollout late";
1994     SetMoveFilter(sz, prcSet->aaamfLate[0]);
1995     SetMoveFilter(sz, prcSet->aaamfLate[1]);
1996 
1997 }
1998 
1999 extern void
2000 CommandSetRolloutPlayerMoveFilter(char *sz)
2001 {
2002 
2003     szSetCommand = "rollout player";
2004     SetMoveFilter(sz, prcSet->aaamfChequer[iPlayerSet]);
2005 
2006 }
2007 
2008 extern void
2009 CommandSetRolloutPlayerLateMoveFilter(char *sz)
2010 {
2011 
2012     szSetCommand = "rollout player late";
2013     SetMoveFilter(sz, prcSet->aaamfLate[iPlayerLateSet]);
2014 
2015 }
2016 
2017 extern void
2018 CommandSetRolloutLateChequerplay(char *sz)
2019 {
2020 
2021     evalcontext *pec[2];
2022 
2023     szSet = _("Chequer play for later moves in rollouts");
2024     szSetCommand = "rollout late chequerplay";
2025 
2026     pec[0] = prcSet->aecChequerLate;
2027     pec[1] = prcSet->aecChequerLate + 1;
2028 
2029     SetRolloutEvaluationContextBoth(sz, pec);
2030 
2031 }
2032 
2033 
2034 static void
2035 SetRolloutEvaluationContext(char *sz, evalcontext * pec[], int iPlayer)
2036 {
2037 
2038     g_assert((iPlayer == 0) || (iPlayer == 1));
2039     g_assert(pec[iPlayer] != 0);
2040 
2041     pecSet = pec[iPlayer];
2042 
2043     HandleCommand(sz, acSetEvaluation);
2044 }
2045 
2046 extern void
2047 CommandSetRolloutPlayerChequerplay(char *sz)
2048 {
2049 
2050     evalcontext *pec[2];
2051 
2052     szSet = iPlayerSet ? _("Chequer play in rollouts (for player 1)") : _("Chequer play in rollouts (for player 0)");
2053     szSetCommand = iPlayerSet ? "rollout player 1 chequerplay" : "rollout player 0 chequerplay";
2054 
2055     pec[0] = prcSet->aecChequer;
2056     pec[1] = prcSet->aecChequer + 1;
2057     SetRolloutEvaluationContext(sz, pec, iPlayerSet);
2058 }
2059 
2060 extern void
2061 CommandSetRolloutPlayerLateChequerplay(char *sz)
2062 {
2063 
2064     evalcontext *pec[2];
2065 
2066     szSet = iPlayerLateSet ?
2067         _("Chequer play for later moves in rollouts (for player 1)") :
2068         _("Chequer play for later moves in rollouts (for player 0)");
2069     szSetCommand = iPlayerLateSet ? "rollout late player 1 chequerplay" : "rollout late player 0 chequerplay";
2070 
2071     pec[0] = prcSet->aecChequerLate;
2072     pec[1] = prcSet->aecChequerLate + 1;
2073     SetRolloutEvaluationContext(sz, pec, iPlayerLateSet);
2074 }
2075 
2076 
2077 extern void
2078 CommandSetRolloutCubedecision(char *sz)
2079 {
2080 
2081     evalcontext *pec[2];
2082 
2083     szSet = _("Cube decisions in rollouts");
2084     szSetCommand = "rollout cubedecision";
2085 
2086     pec[0] = prcSet->aecCube;
2087     pec[1] = prcSet->aecCube + 1;
2088 
2089     SetRolloutEvaluationContextBoth(sz, pec);
2090 
2091 }
2092 
2093 extern void
2094 CommandSetRolloutLateCubedecision(char *sz)
2095 {
2096 
2097     evalcontext *pec[2];
2098 
2099     szSet = _("Cube decisions for later plies in rollouts");
2100     szSetCommand = "rollout late cubedecision";
2101 
2102     pec[0] = prcSet->aecCubeLate;
2103     pec[1] = prcSet->aecCubeLate + 1;
2104 
2105     SetRolloutEvaluationContextBoth(sz, pec);
2106 
2107 }
2108 
2109 extern void
2110 CommandSetRolloutPlayerCubedecision(char *sz)
2111 {
2112 
2113     evalcontext *pec[2];
2114 
2115     szSet = iPlayerSet ? _("Cube decisions in rollouts (for player 1)") :
2116         _("Cube decisions in rollouts (for player 0)");
2117     szSetCommand = iPlayerSet ? "rollout player 1 cubedecision" : "rollout player 0 cubedecision";
2118 
2119     pec[0] = prcSet->aecCube;
2120     pec[1] = prcSet->aecCube + 1;
2121     SetRolloutEvaluationContext(sz, pec, iPlayerSet);
2122 
2123 }
2124 
2125 extern void
2126 CommandSetRolloutPlayerLateCubedecision(char *sz)
2127 {
2128 
2129     evalcontext *pec[2];
2130 
2131     szSet = iPlayerLateSet ? _("Cube decisions for later plies of rollouts (for player 1)") :
2132         _("Cube decisions in later plies of rollouts (for player 0)");
2133     szSetCommand = iPlayerLateSet ? "rollout late player 1 cubedecision" : "rollout late player 0 cubedecision";
2134 
2135     pec[0] = prcSet->aecCubeLate;
2136     pec[1] = prcSet->aecCubeLate + 1;
2137     SetRolloutEvaluationContext(sz, pec, iPlayerLateSet);
2138 
2139 }
2140 
2141 extern void
2142 CommandSetRolloutBearoffTruncationExact(char *sz)
2143 {
2144 
2145     int f = prcSet->fTruncBearoff2;
2146 
2147     SetToggle("rollout bearofftruncation exact", &f, sz,
2148               _("Will truncate *cubeless* rollouts when reaching"
2149                 " exact bearoff database"),
2150               _("Will not truncate *cubeless* rollouts when reaching" " exact bearoff database"));
2151 
2152     prcSet->fTruncBearoff2 = f;
2153 
2154 }
2155 
2156 
2157 extern void
2158 CommandSetRolloutBearoffTruncationOS(char *sz)
2159 {
2160 
2161     int f = prcSet->fTruncBearoffOS;
2162 
2163     SetToggle("rollout bearofftruncation onesided", &f, sz,
2164               _("Will truncate *cubeless* rollouts when reaching"
2165                 " one-sided bearoff database"),
2166               _("Will not truncate *cubeless* rollouts when reaching" " one-sided bearoff database"));
2167 
2168     prcSet->fTruncBearoffOS = f;
2169 
2170 
2171 }
2172 
2173 
2174 extern void
2175 CommandSetRolloutInitial(char *sz)
2176 {
2177 
2178     int f = prcSet->fCubeful;
2179 
2180     SetToggle("rollout initial", &f, sz,
2181               _("Rollouts will be made as the initial position of a game."),
2182               _("Rollouts will be made for normal (non-opening) positions."));
2183 
2184     prcSet->fInitial = f;
2185 }
2186 
2187 extern void
2188 CommandSetRolloutSeed(char *sz)
2189 {
2190 
2191     if (prcSet->rngRollout == RNG_MANUAL) {
2192         outputl(_("You can't set a seed if you're using manual dice " "generation."));
2193         return;
2194     }
2195 
2196     if (*sz) {
2197         const int n = ParseNumber(&sz);
2198 
2199         if (n < 0) {
2200             outputl(_("You must specify a valid seed (see `help set seed')."));
2201 
2202             return;
2203         }
2204 
2205         prcSet->nSeed = n;
2206         outputf(_("Rollout seed set to %d.\n"), n);
2207     } else
2208         outputl(RNGSystemSeed(prcSet->rngRollout, rngctxRollout, NULL) ?
2209                 _("Seed initialised from system random data.") : _("Seed initialised by system clock."));
2210 
2211 }
2212 
2213 extern void
2214 CommandSetRolloutTrials(char *sz)
2215 {
2216 
2217     int n = ParseNumber(&sz);
2218 
2219     if (n < 1) {
2220         outputl(_("You must specify a valid number of trials to make (see `help set rollout trials')."));
2221 
2222         return;
2223     }
2224 
2225     prcSet->nTrials = n;
2226 
2227     outputf(ngettext("%d game will be played per rollout.\n", "%d games will be played per rollout.\n", n), n);
2228 
2229 }
2230 
2231 extern void
2232 CommandSetRolloutTruncationEnable(char *sz)
2233 {
2234     int t = prcSet->fDoTruncate;
2235 
2236     if (SetToggle("rollout truncation enable", &t, sz,
2237                   _("Games in rollouts will be stopped after"
2238                     " a fixed number of moves."), _("Games in rollouts will be played out" " until the end.")) != -1) {
2239         prcSet->fDoTruncate = t;
2240     }
2241 }
2242 
2243 extern void
2244 CommandSetRolloutCubeEqualChequer(char *sz)
2245 {
2246 
2247     SetToggle("rollout cube-equal-chequer", &fCubeEqualChequer, sz,
2248               _("Rollouts use same settings for cube and chequer play."),
2249               _("Rollouts use separate settings for cube and chequer play."));
2250 }
2251 
2252 extern void
2253 CommandSetRolloutPlayersAreSame(char *sz)
2254 {
2255 
2256     SetToggle("rollout players-are-same", &fPlayersAreSame, sz,
2257               _("Rollouts use same settings for both players."), _("Rollouts use separate settings for both players."));
2258 }
2259 
2260 extern void
2261 CommandSetRolloutTruncationEqualPlayer0(char *sz)
2262 {
2263 
2264     SetToggle("rollout truncate-equal-player0", &fTruncEqualPlayer0, sz,
2265               _("Evaluation of rollouts at truncation point will be same as player 0."),
2266               _("Evaluation of rollouts at truncation point are separately specified."));
2267 }
2268 
2269 extern void
2270 CommandSetRolloutTruncationPlies(char *sz)
2271 {
2272 
2273     int n = ParseNumber(&sz);
2274 
2275     if (n < 0) {
2276         outputl(_("You must specify a valid ply at which to truncate rollouts " "(see `help set rollout')."));
2277 
2278         return;
2279     }
2280 
2281     prcSet->nTruncate = (unsigned short) n;
2282 
2283     if ((n == 0) || !prcSet->fDoTruncate)
2284         outputl(_("Rollouts will not be truncated."));
2285     else
2286         outputf(ngettext
2287                 ("Rollouts will be truncated after %d ply.\n", "Rollouts will be truncated after %d plies.\n", n), n);
2288 
2289 }
2290 
2291 extern void
2292 CommandSetRolloutTruncationChequer(char *sz)
2293 {
2294 
2295     szSet = _("Chequer play evaluations at rollout truncation point");
2296     szSetCommand = "rollout truncation chequerplay";
2297 
2298     pecSet = &prcSet->aecChequerTrunc;
2299 
2300     HandleCommand(sz, acSetEvaluation);
2301 }
2302 
2303 extern void
2304 CommandSetRolloutTruncationCube(char *sz)
2305 {
2306 
2307     szSet = _("Cube decisions at rollout truncation point");
2308     szSetCommand = "rollout truncation cubedecision";
2309 
2310     pecSet = &prcSet->aecCubeTrunc;
2311 
2312     HandleCommand(sz, acSetEvaluation);
2313 }
2314 
2315 
2316 extern void
2317 CommandSetRolloutVarRedn(char *sz)
2318 {
2319 
2320     int f = prcSet->fVarRedn;
2321 
2322     SetToggle("rollout varredn", &f, sz,
2323               _("Will use lookahead during rollouts to reduce variance."),
2324               _("Will not use lookahead variance " "reduction during rollouts."));
2325 
2326     prcSet->fVarRedn = f;
2327 }
2328 
2329 
2330 extern void
2331 CommandSetRolloutRotate(char *sz)
2332 {
2333 
2334     int f = prcSet->fRotate;
2335 
2336     SetToggle("rollout quasirandom", &f, sz,
2337               _("Use quasi-random dice in rollouts"), _("Do not use quasi-random dice in rollouts"));
2338 
2339     prcSet->fRotate = f;
2340 
2341 }
2342 
2343 
2344 
2345 extern void
2346 CommandSetRolloutCubeful(char *sz)
2347 {
2348 
2349     int f = prcSet->fCubeful;
2350 
2351     SetToggle("rollout cubeful", &f, sz,
2352               _("Cubeful rollouts will be performed."), _("Cubeless rollouts will be performed."));
2353 
2354     prcSet->fCubeful = f;
2355 }
2356 
2357 
2358 extern void
2359 CommandSetRolloutPlayer(char *sz)
2360 {
2361 
2362     char *pch = NextToken(&sz), *pchCopy;
2363     int i;
2364 
2365     if (!pch) {
2366         outputf(_("You must specify a player (see `help set %s player').\n"), szSetCommand);
2367 
2368         return;
2369     }
2370 
2371     if ((i = ParsePlayer(pch)) == 0 || i == 1) {
2372         iPlayerSet = i;
2373 
2374         HandleCommand(sz, acSetRolloutPlayer);
2375 
2376         return;
2377     }
2378 
2379     if (i == 2) {
2380         if ((pchCopy = malloc(strlen(sz) + 1)) == 0) {
2381             outputl(_("Insufficient memory."));
2382 
2383             return;
2384         }
2385 
2386         strcpy(pchCopy, sz);
2387 
2388         outputpostpone();
2389 
2390         iPlayerSet = 0;
2391         HandleCommand(sz, acSetRolloutPlayer);
2392 
2393         iPlayerSet = 1;
2394         HandleCommand(pchCopy, acSetRolloutPlayer);
2395 
2396         outputresume();
2397 
2398         free(pchCopy);
2399 
2400         return;
2401     }
2402 
2403     outputf(_("Unknown player `%s'\n" "(see `help set %s player').\n"), pch, szSetCommand);
2404 }
2405 
2406 extern void
2407 CommandSetRolloutLatePlayer(char *sz)
2408 {
2409 
2410     char *pch = NextToken(&sz), *pchCopy;
2411     int i;
2412 
2413     if (!pch) {
2414         outputf(_("You must specify a player (see `help set %s player').\n"), szSetCommand);
2415 
2416         return;
2417     }
2418 
2419     if ((i = ParsePlayer(pch)) == 0 || i == 1) {
2420         iPlayerLateSet = i;
2421 
2422         HandleCommand(sz, acSetRolloutLatePlayer);
2423 
2424         return;
2425     }
2426 
2427     if (i == 2) {
2428         if ((pchCopy = malloc(strlen(sz) + 1)) == 0) {
2429             outputl(_("Insufficient memory."));
2430 
2431             return;
2432         }
2433 
2434         strcpy(pchCopy, sz);
2435 
2436         outputpostpone();
2437 
2438         iPlayerLateSet = 0;
2439         HandleCommand(sz, acSetRolloutLatePlayer);
2440 
2441         iPlayerLateSet = 1;
2442         HandleCommand(pchCopy, acSetRolloutLatePlayer);
2443 
2444         outputresume();
2445 
2446         free(pchCopy);
2447 
2448         return;
2449     }
2450 
2451     outputf(_("Unknown player `%s'\n" "(see `help set %s player').\n"), pch, szSetCommand);
2452 }
2453 
2454 extern void
2455 CommandSetScore(char *sz)
2456 {
2457 
2458     moverecord *pmr;
2459     xmovegameinfo *pmgi;
2460     const char *pch0, *pch1, *pch2;
2461     char *pchEnd0, *pchEnd1, *pchEnd2;
2462     int n0, n1, n, fCrawford0, fCrawford1, fPostCrawford0, fPostCrawford1;
2463 
2464     if ((pch0 = NextToken(&sz)) == 0)
2465         pch0 = "";
2466 
2467     if ((pch1 = NextToken(&sz)) == 0)
2468         pch1 = "";
2469 
2470     if ((pch2 = NextToken(&sz)) != 0) {
2471         n = (int) strtol(pch2, &pchEnd2, 10);
2472         if (pch2 == pchEnd2 || n < 0 || n > MAXSCORE) {
2473             outputf(_("Match length must be between 0 (unlimited session) and %d\n"), MAXSCORE);
2474             return;
2475         } else
2476             ms.nMatchTo = n;
2477     }
2478 
2479     n0 = (int) strtol(pch0, &pchEnd0, 10);
2480     if (pch0 == pchEnd0)
2481         n0 = INT_MIN;
2482 
2483     n1 = (int) strtol(pch1, &pchEnd1, 10);
2484     if (pch1 == pchEnd1)
2485         n1 = INT_MIN;
2486 
2487     if (((fCrawford0 = *pchEnd0 == '*' ||
2488           (*pchEnd0 && !StrNCaseCmp(pchEnd0, "crawford",
2489                                     strlen(pchEnd0)))) &&
2490          n0 != INT_MIN && n0 != -1 && n0 != ms.nMatchTo - 1) ||
2491         ((fCrawford1 = *pchEnd1 == '*' ||
2492           (*pchEnd1 && !StrNCaseCmp(pchEnd1, "crawford",
2493                                     strlen(pchEnd1)))) && n1 != INT_MIN && n1 != -1 && n1 != ms.nMatchTo - 1)) {
2494         outputl(_("The Crawford rule applies only in match play when a " "player's score is 1-away."));
2495         return;
2496     }
2497 
2498     if (((fPostCrawford0 = (*pchEnd0 && !StrNCaseCmp(pchEnd0, "postcrawford", strlen(pchEnd0)))) &&
2499          n0 != INT_MIN && n0 != -1 && n0 != ms.nMatchTo - 1) ||
2500         ((fPostCrawford1 = (*pchEnd1 && !StrNCaseCmp(pchEnd1, "postcrawford", strlen(pchEnd1)))) &&
2501          n1 != INT_MIN && n1 != -1 && n1 != ms.nMatchTo - 1)) {
2502         outputl(_("The Crawford rule applies only in match play when a " "player's score is 1-away."));
2503         return;
2504     }
2505 
2506     if (!ms.nMatchTo && (fCrawford0 || fCrawford1 || fPostCrawford0 || fPostCrawford1)) {
2507         outputl(_("The Crawford rule applies only in match play when a " "player's score is 1-away."));
2508         return;
2509     }
2510 
2511     if (fCrawford0 && fCrawford1) {
2512         outputl(_("You cannot set the Crawford rule when both players' scores " "are 1-away."));
2513         return;
2514     }
2515 
2516     if ((fCrawford0 && fPostCrawford1) || (fCrawford1 && fPostCrawford0)) {
2517         outputl(_("You cannot set both Crawford and post-Crawford " "simultaneously."));
2518         return;
2519     }
2520 
2521     /* silently ignore the case where both players are set post-Crawford;
2522      * assume that is unambiguous and means double match point */
2523 
2524     if (fCrawford0 || fPostCrawford0)
2525         n0 = -1;
2526 
2527     if (fCrawford1 || fPostCrawford1)
2528         n1 = -1;
2529 
2530     if (n0 < 0)                 /* -n means n-away */
2531         n0 += ms.nMatchTo;
2532 
2533     if (n1 < 0)
2534         n1 += ms.nMatchTo;
2535 
2536     if ((fPostCrawford0 && !n1) || (fPostCrawford1 && !n0)) {
2537         outputl(_("You cannot set post-Crawford play if the trailer has yet " "to score."));
2538         return;
2539     }
2540 
2541     if (n0 < 0 || n1 < 0) {
2542         outputl(_("You must specify two valid scores."));
2543         return;
2544     }
2545 
2546     if (ms.nMatchTo && n0 >= ms.nMatchTo && n1 >= ms.nMatchTo) {
2547         outputl(_("Only one player may win the match."));
2548         return;
2549     }
2550 
2551     if ((fCrawford0 || fCrawford1) && (n0 >= ms.nMatchTo || n1 >= ms.nMatchTo)) {
2552         outputl(_("You cannot play the Crawford game once the match is " "already over."));
2553         return;
2554     }
2555 
2556     /* allow scores above the match length, since that doesn't really
2557      * hurt anything */
2558 
2559     CancelCubeAction();
2560 
2561     ms.anScore[0] = n0;
2562     ms.anScore[1] = n1;
2563 
2564     if (ms.nMatchTo) {
2565         if (n0 != ms.nMatchTo - 1 && n1 != ms.nMatchTo - 1)
2566             /* must be pre-Crawford */
2567             ms.fCrawford = ms.fPostCrawford = FALSE;
2568         else if ((n0 == ms.nMatchTo - 1 && n1 == ms.nMatchTo - 1) || fPostCrawford0 || fPostCrawford1) {
2569             /* must be post-Crawford */
2570             ms.fCrawford = FALSE;
2571             ms.fPostCrawford = ms.nMatchTo > 1;
2572         } else {
2573             /* possibly the Crawford game */
2574             if (n0 >= ms.nMatchTo || n1 >= ms.nMatchTo)
2575                 ms.fCrawford = FALSE;
2576             else if (fCrawford0 || fCrawford1 || !n0 || !n1)
2577                 ms.fCrawford = TRUE;
2578 
2579             ms.fPostCrawford = !ms.fCrawford;
2580         }
2581     }
2582 
2583     if (ms.gs < GAME_OVER && plGame && (pmr = (moverecord *) plGame->plNext->p) && (pmgi = &pmr->g)) {
2584         g_assert(pmr->mt == MOVE_GAMEINFO);
2585         pmgi->anScore[0] = ms.anScore[0];
2586         pmgi->anScore[1] = ms.anScore[1];
2587         pmgi->fCrawfordGame = ms.fCrawford;
2588 #if defined(USE_GTK)
2589         /* The score this game was started at is displayed in the option
2590          * menu, and is now out of date. */
2591         if (fX)
2592             GTKRegenerateGames();
2593 #endif                          /* USE_GTK */
2594     }
2595 
2596     CommandShowScore(NULL);
2597 
2598 #if defined(USE_GTK)
2599     if (fX)
2600         ShowBoard();
2601 #endif                          /* USE_GTK */
2602 }
2603 
2604 extern void
2605 CommandSetSeed(char *sz)
2606 {
2607     SetSeed(rngCurrent, rngctxCurrent, sz);
2608 }
2609 
2610 extern void
2611 CommandSetToolbar(char *sz)
2612 {
2613     if (!StrCaseCmp("on", sz) || !StrCaseCmp("off", sz)) {
2614 #if defined(USE_GTK)
2615         if (!StrCaseCmp("on", sz)) {
2616             if (!fToolbarShowing)
2617                 ShowToolbar();
2618         } else {
2619             if (fToolbarShowing)
2620                 HideToolbar();
2621         }
2622 #endif
2623     } else {
2624         int n = ParseNumber(&sz);
2625 
2626         if (n != 0 && n != 1 && n != 2) {
2627             outputl(_("You must specify either 0, 1 or 2"));
2628             return;
2629         }
2630 #if defined(USE_GTK)
2631         if (fX)
2632             SetToolbarStyle(n);
2633 #endif
2634     }
2635 }
2636 
2637 extern void
2638 SetTurn(int i)
2639 {
2640     if (ms.fTurn != i)
2641         SwapSides(ms.anBoard);
2642 
2643     ms.fTurn = ms.fMove = i;
2644     CancelCubeAction();
2645     pmr_hint_destroy();
2646     fNextTurn = FALSE;
2647 #if defined(USE_GTK)
2648     if (fX) {
2649         BoardData *bd = BOARD(pwBoard)->board_data;
2650         bd->diceRoll[0] = bd->diceRoll[1] = 0;
2651         fJustSwappedPlayers = TRUE;
2652     }
2653 #endif
2654     ms.anDice[0] = ms.anDice[1] = 0;
2655 
2656 
2657     UpdateSetting(&ms.fTurn);
2658 
2659 #if defined(USE_GTK)
2660     if (fX)
2661         ShowBoard();
2662 #endif                          /* USE_GTK */
2663 
2664     return;
2665 }
2666 
2667 extern void
2668 CommandSetTurn(char *sz)
2669 {
2670 
2671     char *pch = NextToken(&sz);
2672     int i;
2673 
2674     if (ms.gs != GAME_PLAYING) {
2675         outputl(_("There must be a game in progress to set a player on roll."));
2676 
2677         return;
2678     }
2679 
2680     if (ms.fResigned) {
2681         outputl(_("Please resolve the resignation first."));
2682 
2683         return;
2684     }
2685 
2686     if (!pch) {
2687         outputl(_("Which player do you want to set on roll?"));
2688 
2689         return;
2690     }
2691 
2692     if ((i = ParsePlayer(pch)) < 0) {
2693         outputf(_("Unknown player `%s' (see `help set turn').\n"), pch);
2694 
2695         return;
2696     }
2697 
2698     if (i == 2) {
2699         outputl(_("You can't set both players on roll."));
2700 
2701         return;
2702     }
2703 
2704     SetTurn(i);
2705 
2706     outputf(_("`%s' is now on roll.\n"), ap[i].szName);
2707 }
2708 
2709 extern void
2710 CommandSetJacoby(char *sz)
2711 {
2712 
2713     if (SetToggle("jacoby", &fJacoby, sz,
2714                   _("Will use the Jacoby rule for money sessions."),
2715                   _("Will not use the Jacoby rule for money sessions.")))
2716         return;
2717 
2718     if (fJacoby && !ms.fCubeUse)
2719         outputl(_("Note that you'll have to enable the cube if you want "
2720                   "gammons and backgammons\nto be scored (see `help set " "cube use')."));
2721 
2722     ms.fJacoby = fJacoby;
2723 
2724 }
2725 
2726 extern void
2727 CommandSetCrawford(char *sz)
2728 {
2729 
2730     moverecord *pmr;
2731     xmovegameinfo *pmgi;
2732 
2733     if (ms.nMatchTo > 0) {
2734         if ((ms.nMatchTo - ms.anScore[0] == 1) || (ms.nMatchTo - ms.anScore[1] == 1)) {
2735 
2736             if (SetToggle("crawford", &ms.fCrawford, sz,
2737                           _("This game is the Crawford game (no doubling allowed)."),
2738                           _("This game is not the Crawford game.")) < 0)
2739                 return;
2740 
2741             /* sanity check */
2742             ms.fPostCrawford = !ms.fCrawford;
2743 
2744             if (ms.fCrawford)
2745                 CancelCubeAction();
2746 
2747             if (plGame && (pmr = plGame->plNext->p) && (pmgi = &pmr->g)) {
2748                 g_assert(pmr->mt == MOVE_GAMEINFO);
2749                 pmgi->fCrawfordGame = ms.fCrawford;
2750             }
2751         } else {
2752             if (ms.fCrawford) { /* Allow crawford to be turned off if set at incorrect score */
2753                 SetToggle("crawford", &ms.fCrawford, sz,
2754                           _("This game is the Crawford game (no doubling allowed)."),
2755                           _("This game is not the Crawford game."));
2756                 return;
2757             }
2758             outputl(_("Cannot set whether this is the Crawford game\n"
2759                       "as none of the players are 1-away from winning."));
2760         }
2761         /* Clear previous data in the hint cache after toggling Crawford */
2762         pmr_hint_destroy();
2763     } else if (!ms.nMatchTo)
2764         outputl(_("Cannot set Crawford play for money sessions."));
2765     else
2766         outputl(_("No match in progress (type `new match n' to start one)."));
2767 }
2768 
2769 extern void
2770 CommandSetPostCrawford(char *sz)
2771 {
2772 
2773     moverecord *pmr;
2774     xmovegameinfo *pmgi;
2775 
2776     if (ms.nMatchTo > 0) {
2777         if ((ms.nMatchTo - ms.anScore[0] == 1) || (ms.nMatchTo - ms.anScore[1] == 1)) {
2778 
2779             SetToggle("postcrawford", &ms.fPostCrawford, sz,
2780                       _("This is post-Crawford play (doubling allowed)."), _("This is not post-Crawford play."));
2781 
2782             /* sanity check */
2783             ms.fCrawford = !ms.fPostCrawford;
2784 
2785             if (ms.fCrawford)
2786                 CancelCubeAction();
2787 
2788             if (plGame && (pmr = plGame->plNext->p) && (pmgi = &pmr->g)) {
2789                 g_assert(pmr->mt == MOVE_GAMEINFO);
2790                 pmgi->fCrawfordGame = ms.fCrawford;
2791             }
2792         } else {
2793             outputl(_("Cannot set whether this is post-Crawford play\n"
2794                       "as none of the players are 1-away from winning."));
2795         }
2796     } else if (!ms.nMatchTo)
2797         outputl(_("Cannot set post-Crawford play for money sessions."));
2798     else
2799         outputl(_("No match in progress (type `new match n' to start one)."));
2800 
2801 }
2802 
2803 #if defined(USE_GTK)
2804 extern void
2805 CommandSetWarning(char *sz)
2806 {
2807     char buf[100];
2808     warningType warning;
2809     char *pValue = strchr(sz, ' ');
2810 
2811     if (!pValue) {
2812         outputl(_("Incorrect syntax for set warning command."));
2813         return;
2814     }
2815     *pValue++ = '\0';
2816 
2817     warning = ParseWarning(sz);
2818     if ((int) warning < 0) {
2819         sprintf(buf, _("Unknown warning %s."), sz);
2820         outputl(buf);
2821         return;
2822     }
2823 
2824     while (*pValue == ' ')
2825         pValue++;
2826 
2827     if (!StrCaseCmp(pValue, "on")) {
2828         SetWarningEnabled(warning, TRUE);
2829     } else if (!StrCaseCmp(pValue, "off")) {
2830         SetWarningEnabled(warning, FALSE);
2831     } else {
2832         sprintf(buf, _("Unknown value %s."), pValue);
2833         outputl(buf);
2834         return;
2835     }
2836     sprintf(buf, _("Warning %s set to %s."), sz, pValue);
2837     outputl(buf);
2838 }
2839 
2840 extern void
2841 CommandShowWarning(char *sz)
2842 {
2843     warningType warning;
2844 
2845     while (*sz == ' ')
2846         sz++;
2847 
2848     if (!*sz) {                 /* Show all warnings */
2849         for (warning = (warningType) 0; warning < WARN_NUM_WARNINGS; warning++)
2850             PrintWarning(warning);
2851     } else {                    /* Show specific warning */
2852         warning = ParseWarning(sz);
2853         if ((int) warning < 0) {
2854             char buf[100];
2855             sprintf(buf, _("Unknown warning %s."), sz);
2856             outputl(buf);
2857             return;
2858         }
2859         PrintWarning(warning);
2860     }
2861 }
2862 #endif
2863 
2864 extern void
2865 CommandSetBeavers(char *sz)
2866 {
2867 
2868     int n;
2869 
2870     if ((n = ParseNumber(&sz)) < 0) {
2871         outputl(_("You must specify the number of beavers to allow."));
2872 
2873         return;
2874     }
2875 
2876     nBeavers = (unsigned int) n;
2877 
2878     if (nBeavers > 1)
2879         outputf(_("%u beavers/raccoons allowed in money sessions.\n"), nBeavers);
2880     else if (nBeavers == 1)
2881         outputl(_("1 beaver allowed in money sessions."));
2882     else
2883         outputl(_("No beavers allowed in money sessions."));
2884 }
2885 
2886 extern void
2887 CommandSetOutputDigits(char *sz)
2888 {
2889 
2890     int n = ParseNumber(&sz);
2891 
2892     if (n < 0 || n > MAX_OUTPUT_DIGITS) {
2893         outputf(_("You must specify a number between 1 and %d.\n"), MAX_OUTPUT_DIGITS);
2894         return;
2895     }
2896 
2897     fOutputDigits = n;
2898 
2899     outputf(_("Probabilities and equities will be shown with %d digits "
2900               "after the decimal separator\n"), fOutputDigits);
2901 
2902 #if defined(USE_GTK)
2903     MoveListRefreshSize();
2904 #endif
2905 }
2906 
2907 
2908 extern void
2909 CommandSetOutputMatchPC(char *sz)
2910 {
2911 
2912     SetToggle("output matchpc", &fOutputMatchPC, sz,
2913               _("Match winning chances will be shown as percentages."),
2914               _("Match winning chances will be shown as probabilities."));
2915 }
2916 
2917 extern void
2918 CommandSetOutputMWC(char *sz)
2919 {
2920 
2921     SetToggle("output mwc", &fOutputMWC, sz,
2922               _("Match evaluations will be shown as match winning chances."),
2923               _("Match evaluations will be shown as equivalent money equity."));
2924 }
2925 
2926 extern void
2927 CommandSetOutputRawboard(char *sz)
2928 {
2929 
2930     SetToggle("output rawboard", &fOutputRawboard, sz,
2931               _("TTY boards will be given in raw format."), _("TTY boards will be given in ASCII."));
2932 }
2933 
2934 extern void
2935 CommandSetOutputWinPC(char *sz)
2936 {
2937 
2938     SetToggle("output winpc", &fOutputWinPC, sz,
2939               _("Game winning chances will be shown as percentages."),
2940               _("Game winning chances will be shown as probabilities."));
2941 }
2942 
2943 static void
2944 SetInvertMET(void)
2945 {
2946     invertMET();
2947     /* Clear any stored results to stop previous table causing problems */
2948     EvalCacheFlush();
2949     pmr_hint_destroy();
2950 }
2951 
2952 extern void
2953 CommandSetMET(char *sz)
2954 {
2955 
2956     sz = NextToken(&sz);
2957 
2958     if (!sz || !*sz) {
2959         outputl(_("You must specify a filename. " "See \"help set met\". "));
2960         return;
2961     }
2962 
2963     InitMatchEquity(sz);
2964     /* Cubeful evaluation get confused with entries from another table */
2965     EvalCacheFlush();
2966 
2967     /* clear hint */
2968     CommandClearHint(NULL);
2969 
2970     outputf(_("GNU Backgammon will now use the %s match equity table.\n"), miCurrent.szName);
2971 
2972     if (miCurrent.nLength < MAXSCORE && miCurrent.nLength != -1) {
2973 
2974         outputf(_("\n"
2975                   "Note that this match equity table only supports "
2976                   "matches of length %i and below.\n"
2977                   "For scores above %i-away an extrapolation "
2978                   "scheme is used.\n"), miCurrent.nLength, miCurrent.nLength);
2979 
2980     }
2981     if (fInvertMET)
2982         SetInvertMET();
2983 }
2984 
2985 extern void
2986 CommandSetEvalParamType(char *sz)
2987 {
2988     switch (sz[0]) {
2989 
2990     case 'r':
2991         pesSet->et = EVAL_ROLLOUT;
2992         break;
2993 
2994     case 'e':
2995         pesSet->et = EVAL_EVAL;
2996         break;
2997 
2998     default:
2999         outputf(_("Unknown evaluation type: %s (see\n" "`help set %s type').\n"), sz, szSetCommand);
3000         return;
3001 
3002     }
3003 
3004     outputf(_("%s will now use %s.\n"), szSet, gettext(aszEvalType[pesSet->et]));
3005 }
3006 
3007 
3008 extern void
3009 CommandSetEvalParamEvaluation(char *sz)
3010 {
3011 
3012     pecSet = &pesSet->ec;
3013 
3014     HandleCommand(sz, acSetEvaluation);
3015 
3016     if (pesSet->et != EVAL_EVAL)
3017         outputf(_("(Note that this setting will have no effect until you\n"
3018                   "`set %s type evaluation'.)\n"), szSetCommand);
3019 }
3020 
3021 
3022 extern void
3023 CommandSetEvalParamRollout(char *sz)
3024 {
3025 
3026     prcSet = &pesSet->rc;
3027 
3028     HandleCommand(sz, acSetRollout);
3029 
3030     if (pesSet->et != EVAL_ROLLOUT)
3031         outputf(_("(Note that this setting will have no effect until you\n" "`set %s type rollout.)'\n"), szSetCommand);
3032 
3033 }
3034 
3035 extern void
3036 CommandSetEvalSameAsAnalysis(char *sz)
3037 {
3038     SetToggle("eval sameasanalysis", &fEvalSameAsAnalysis, sz,
3039               _("Evaluation settings will be same as analysis settings."),
3040               _("Evaluation settings separate from analysis settings."));
3041 }
3042 
3043 extern void
3044 CommandSetAnalysisPlayer(char *sz)
3045 {
3046 
3047     char *pch = NextToken(&sz), *pchCopy;
3048     int i;
3049 
3050     if (!pch) {
3051         outputl(_("You must specify a player " "(see `help set analysis player')."));
3052         return;
3053     }
3054 
3055     if ((i = ParsePlayer(pch)) == 0 || i == 1) {
3056         iPlayerSet = i;
3057 
3058         HandleCommand(sz, acSetAnalysisPlayer);
3059 
3060         return;
3061     }
3062 
3063     if (i == 2) {
3064         if ((pchCopy = malloc(strlen(sz) + 1)) == 0) {
3065             outputl(_("Insufficient memory."));
3066 
3067             return;
3068         }
3069 
3070         strcpy(pchCopy, sz);
3071 
3072         outputpostpone();
3073 
3074         iPlayerSet = 0;
3075         HandleCommand(sz, acSetAnalysisPlayer);
3076 
3077         iPlayerSet = 1;
3078         HandleCommand(pchCopy, acSetAnalysisPlayer);
3079 
3080         outputresume();
3081 
3082         free(pchCopy);
3083 
3084         return;
3085     }
3086 
3087     outputf(_("Unknown player `%s'\n" "(see `help set analysis player').\n"), pch);
3088 
3089 }
3090 
3091 
3092 extern void
3093 CommandSetAnalysisPlayerAnalyse(char *sz)
3094 {
3095 
3096     char sz1[100];
3097     char sz2[100];
3098 
3099     sprintf(sz1, _("Analyse %s's chequerplay and cube decisions."), ap[iPlayerSet].szName);
3100 
3101     sprintf(sz2, _("Do not analyse %s's chequerplay and cube decisions."), ap[iPlayerSet].szName);
3102 
3103     SetToggle("analysis player", &afAnalysePlayers[iPlayerSet], sz, sz1, sz2);
3104 
3105 }
3106 
3107 
3108 extern void
3109 CommandSetAnalysisChequerplay(char *sz)
3110 {
3111 
3112     pesSet = &esAnalysisChequer;
3113 
3114     szSet = _("Analysis chequerplay");
3115     szSetCommand = "analysis chequerplay";
3116 
3117     HandleCommand(sz, acSetEvalParam);
3118 
3119 }
3120 
3121 extern void
3122 CommandSetAnalysisCubedecision(char *sz)
3123 {
3124 
3125 
3126     pesSet = &esAnalysisCube;
3127 
3128     szSet = _("Analysis cubedecision");
3129     szSetCommand = "analysis cubedecision";
3130 
3131     HandleCommand(sz, acSetEvalParam);
3132 
3133 }
3134 
3135 
3136 extern void
3137 CommandSetEvalChequerplay(char *sz)
3138 {
3139 
3140     pesSet = &esEvalChequer;
3141 
3142     szSet = _("`eval' and `hint' chequerplay");
3143     szSetCommand = "evaluation chequerplay ";
3144 
3145     HandleCommand(sz, acSetEvalParam);
3146 
3147 }
3148 
3149 extern void
3150 CommandSetEvalCubedecision(char *sz)
3151 {
3152 
3153 
3154     pesSet = &esEvalCube;
3155 
3156     szSet = _("`eval' and `hint' cube decisions");
3157     szSetCommand = "evaluation cubedecision ";
3158 
3159     HandleCommand(sz, acSetEvalParam);
3160 
3161 }
3162 
3163 
3164 extern void
3165 CommandSetEvalMoveFilter(char *sz)
3166 {
3167 
3168     szSetCommand = "evaluation";
3169     SetMoveFilter(sz, aamfEval);
3170 
3171 }
3172 
3173 extern void
3174 CommandSetAnalysisMoveFilter(char *sz)
3175 {
3176 
3177     szSetCommand = "analysis";
3178     SetMoveFilter(sz, aamfAnalysis);
3179 
3180 }
3181 
3182 
3183 
3184 
3185 extern void
3186 SetMatchInfo(char **ppch, const char *sz, char *szMessage)
3187 {
3188     if (*ppch)
3189         g_free(*ppch);
3190 
3191     if (sz && *sz) {
3192         *ppch = g_strdup(sz);
3193         if (szMessage)
3194             outputf(_("%s set to: %s\n"), szMessage, sz);
3195     } else {
3196         *ppch = NULL;
3197         if (szMessage)
3198             outputf(_("%s cleared.\n"), szMessage);
3199     }
3200 }
3201 
3202 extern void
3203 CommandSetMatchAnnotator(char *sz)
3204 {
3205 
3206     SetMatchInfo(&mi.pchAnnotator, sz, _("Match annotator"));
3207 }
3208 
3209 extern void
3210 CommandSetMatchComment(char *sz)
3211 {
3212 
3213     SetMatchInfo(&mi.pchComment, sz, _("Match comment"));
3214 }
3215 
3216 static int
3217 DaysInMonth(int nYear, int nMonth)
3218 {
3219 
3220     static int an[12] = { 31, -1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
3221 
3222     if (nMonth < 1 || nMonth > 12)
3223         return -1;
3224     else if (nMonth != 2)
3225         return an[nMonth - 1];
3226     else if (nYear % 4 || (!(nYear % 100) && nYear % 400))
3227         return 28;
3228     else
3229         return 29;
3230 }
3231 
3232 extern void
3233 CommandSetMatchDate(char *sz)
3234 {
3235 
3236     int nYear, nMonth, nDay;
3237 
3238     if (!sz || !*sz) {
3239         mi.nYear = 0;
3240         outputl(_("Match date cleared."));
3241         return;
3242     }
3243 
3244     if (sscanf(sz, "%4d-%2d-%2d", &nYear, &nMonth, &nDay) < 3 ||
3245         nYear < 1753 || nMonth < 1 || nMonth > 12 || nDay < 1 || nDay > DaysInMonth(nYear, nMonth)) {
3246         outputf(_("%s is not a valid date (see `help set matchinfo " "date').\n"), sz);
3247         return;
3248     }
3249 
3250     mi.nYear = nYear;
3251     mi.nMonth = nMonth;
3252     mi.nDay = nDay;
3253 
3254     outputf(_("Match date set to %04d-%02d-%02d.\n"), nYear, nMonth, nDay);
3255 }
3256 
3257 extern void
3258 CommandSetMatchEvent(char *sz)
3259 {
3260 
3261     SetMatchInfo(&mi.pchEvent, sz, _("Match event"));
3262 }
3263 
3264 extern void
3265 CommandSetMatchLength(char *sz)
3266 {
3267 
3268     int n;
3269 
3270     if ((n = ParseNumber(&sz)) < 0 || n > MAXSCORE) {
3271         outputf(_("Match length must be between 0 (unlimited session) and %d\n"), MAXSCORE);
3272         return;
3273     }
3274 
3275     nDefaultLength = (unsigned) n;
3276 
3277     outputf(ngettext("New matches default to %u point.\n", "New matches default to %u points.\n", nDefaultLength),
3278             nDefaultLength);
3279 
3280 }
3281 
3282 extern void
3283 CommandSetMatchPlace(char *sz)
3284 {
3285 
3286     SetMatchInfo(&mi.pchPlace, sz, _("Match place"));
3287 }
3288 
3289 extern void
3290 CommandSetMatchRating(char *sz)
3291 {
3292 
3293     int n;
3294     char szMessage[64];
3295 
3296     if ((n = ParsePlayer(NextToken(&sz))) < 0) {
3297         outputl(_("You must specify which player's rating to set (see `help " "set matchinfo rating')."));
3298         return;
3299     }
3300 
3301     sprintf(szMessage, _("Rating for %s"), ap[n].szName);
3302 
3303     SetMatchInfo(&mi.pchRating[n], sz, szMessage);
3304 }
3305 
3306 extern void
3307 CommandSetMatchRound(char *sz)
3308 {
3309 
3310     SetMatchInfo(&mi.pchRound, sz, _("Match round"));
3311 
3312 }
3313 
3314 extern void
3315 CommandSetMatchID(char *sz)
3316 {
3317 
3318     SetMatchID(sz);
3319 
3320 }
3321 
3322 extern void
3323 CommandSetExportIncludeAnnotations(char *sz)
3324 {
3325 
3326     SetToggle("annotations", &exsExport.fIncludeAnnotation, sz,
3327               _("Include annotations in exports"), _("Do not include annotations in exports"));
3328 
3329 }
3330 
3331 extern void
3332 CommandSetExportIncludeAnalysis(char *sz)
3333 {
3334 
3335     SetToggle("analysis", &exsExport.fIncludeAnalysis, sz,
3336               _("Include analysis in exports"), _("Do not include analysis in exports"));
3337 
3338 }
3339 
3340 extern void
3341 CommandSetExportIncludeStatistics(char *sz)
3342 {
3343 
3344     SetToggle("statistics", &exsExport.fIncludeStatistics, sz,
3345               _("Include statistics in exports"), _("Do not include statistics in exports"));
3346 
3347 }
3348 
3349 extern void
3350 CommandSetExportIncludeMatchInfo(char *sz)
3351 {
3352 
3353     SetToggle("matchinfo", &exsExport.fIncludeMatchInfo, sz,
3354               _("Include match information in exports"), _("Do not include match information in exports"));
3355 
3356 }
3357 
3358 extern void
3359 CommandSetExportShowBoard(char *sz)
3360 {
3361 
3362     int n;
3363 
3364     if ((n = ParseNumber(&sz)) < 0) {
3365         outputl(_("You must specify a semi-positive number."));
3366 
3367         return;
3368     }
3369 
3370     exsExport.fDisplayBoard = n;
3371 
3372     if (!n)
3373         output(_("The board will never been shown in exports."));
3374     else
3375         outputf(_("The board will be shown every %d. move in exports."), n);
3376 
3377 }
3378 
3379 
3380 extern void
3381 CommandSetExportShowPlayer(char *sz)
3382 {
3383 
3384     int i;
3385 
3386     if ((i = ParsePlayer(sz)) < 0) {
3387         outputf(_("Unknown player `%s' " "(see `help set export show player').\n"), sz);
3388         return;
3389     }
3390 
3391     exsExport.fSide = i + 1;
3392 
3393     if (i == 2)
3394         outputl(_("Analysis, boards etc will be " "shown for both players in exports."));
3395     else
3396         outputf(_("Analysis, boards etc will only be shown for " "player %s in exports.\n"), ap[i].szName);
3397 
3398 }
3399 
3400 
3401 extern void
3402 CommandSetExportMovesNumber(char *sz)
3403 {
3404 
3405     int n;
3406 
3407     if ((n = ParseNumber(&sz)) < 0) {
3408         outputl(_("You must specify a semi-positive number."));
3409 
3410         return;
3411     }
3412 
3413     exsExport.nMoves = n;
3414 
3415     outputf(_("Show at most %d moves in exports.\n"), n);
3416 
3417 }
3418 
3419 extern void
3420 CommandSetExportMovesProb(char *sz)
3421 {
3422 
3423     SetToggle("probabilities", &exsExport.fMovesDetailProb, sz,
3424               _("Show detailed probabilities for moves"), _("Do not show detailed probabilities for moves"));
3425 
3426 }
3427 
3428 static int *pParameter;
3429 
3430 extern void
3431 CommandSetExportMovesParameters(char *sz)
3432 {
3433 
3434     pParameter = exsExport.afMovesParameters;
3435     HandleCommand(sz, acSetExportParameters);
3436 
3437 }
3438 
3439 extern void
3440 CommandSetExportCubeProb(char *sz)
3441 {
3442 
3443     SetToggle("probabilities", &exsExport.fCubeDetailProb, sz,
3444               _("Show detailed probabilities for cube decisions"),
3445               _("Do not show detailed probabilities for cube decisions"));
3446 
3447 }
3448 
3449 extern void
3450 CommandSetExportCubeParameters(char *sz)
3451 {
3452 
3453 
3454     pParameter = exsExport.afCubeParameters;
3455     HandleCommand(sz, acSetExportParameters);
3456 
3457 }
3458 
3459 
3460 extern void
3461 CommandSetExportParametersEvaluation(char *sz)
3462 {
3463 
3464     SetToggle("evaluation", &pParameter[0], sz,
3465               _("Show detailed parameters for evaluations"), _("Do not show detailed parameters for evaluations"));
3466 
3467 }
3468 
3469 extern void
3470 CommandSetExportParametersRollout(char *sz)
3471 {
3472 
3473     SetToggle("rollout", &pParameter[1], sz,
3474               _("Show detailed parameters for rollouts"), _("Do not show detailed parameters for rollouts"));
3475 
3476 }
3477 
3478 
3479 extern void
3480 CommandSetExportMovesDisplayVeryBad(char *sz)
3481 {
3482 
3483     SetToggle("export moves display very bad",
3484               &exsExport.afMovesDisplay[SKILL_VERYBAD], sz,
3485               _("Export moves marked 'very bad'."), _("Do not export moves marked 'very bad'."));
3486 
3487 }
3488 
3489 extern void
3490 CommandSetExportMovesDisplayBad(char *sz)
3491 {
3492 
3493     SetToggle("export moves display bad",
3494               &exsExport.afMovesDisplay[SKILL_BAD], sz,
3495               _("Export moves marked 'bad'."), _("Do not export moves marked 'bad'."));
3496 
3497 }
3498 
3499 extern void
3500 CommandSetExportMovesDisplayDoubtful(char *sz)
3501 {
3502 
3503     SetToggle("export moves display doubtful",
3504               &exsExport.afMovesDisplay[SKILL_DOUBTFUL], sz,
3505               _("Export moves marked 'doubtful'."), _("Do not export moves marked 'doubtful'."));
3506 
3507 }
3508 
3509 extern void
3510 CommandSetExportMovesDisplayUnmarked(char *sz)
3511 {
3512 
3513     SetToggle("export moves display unmarked",
3514               &exsExport.afMovesDisplay[SKILL_NONE], sz,
3515               _("Export unmarked moves."), _("Do not export unmarked moves."));
3516 
3517 }
3518 
3519 extern void
3520 CommandSetExportCubeDisplayVeryBad(char *sz)
3521 {
3522 
3523     SetToggle("export cube display very bad",
3524               &exsExport.afCubeDisplay[SKILL_VERYBAD], sz,
3525               _("Export cube decisions marked 'very bad'."), _("Do not export cube decisions marked 'very bad'."));
3526 
3527 }
3528 
3529 extern void
3530 CommandSetExportCubeDisplayBad(char *sz)
3531 {
3532 
3533     SetToggle("export cube display bad",
3534               &exsExport.afCubeDisplay[SKILL_BAD], sz,
3535               _("Export cube decisions marked 'bad'."), _("Do not export cube decisions marked 'bad'."));
3536 
3537 }
3538 
3539 extern void
3540 CommandSetExportCubeDisplayDoubtful(char *sz)
3541 {
3542 
3543     SetToggle("export cube display doubtful",
3544               &exsExport.afCubeDisplay[SKILL_DOUBTFUL], sz,
3545               _("Export cube decisions marked 'doubtful'."), _("Do not export cube decisions marked 'doubtful'."));
3546 
3547 }
3548 
3549 extern void
3550 CommandSetExportCubeDisplayUnmarked(char *sz)
3551 {
3552 
3553     SetToggle("export cube display unmarked",
3554               &exsExport.afCubeDisplay[SKILL_NONE], sz,
3555               _("Export unmarked cube decisions."), _("Do not export unmarked cube decisions."));
3556 
3557 }
3558 
3559 extern void
3560 CommandSetExportCubeDisplayActual(char *sz)
3561 {
3562 
3563     SetToggle("export cube display actual",
3564               &exsExport.afCubeDisplay[EXPORT_CUBE_ACTUAL], sz,
3565               _("Export actual cube decisions."), _("Do not export actual cube decisions."));
3566 
3567 }
3568 
3569 extern void
3570 CommandSetExportCubeDisplayClose(char *sz)
3571 {
3572 
3573     SetToggle("export cube display close",
3574               &exsExport.afCubeDisplay[EXPORT_CUBE_CLOSE], sz,
3575               _("Export close cube decisions."), _("Do not export close cube decisions."));
3576 
3577 }
3578 
3579 extern void
3580 CommandSetExportCubeDisplayMissed(char *sz)
3581 {
3582 
3583     SetToggle("export cube display missed",
3584               &exsExport.afCubeDisplay[EXPORT_CUBE_MISSED], sz,
3585               _("Export missed cube decisions."), _("Do not export missed cube decisions."));
3586 
3587 }
3588 
3589 static void
3590 SetExportHTMLType(const htmlexporttype het, const char *szExtension)
3591 {
3592 
3593     if (exsExport.szHTMLExtension)
3594         g_free(exsExport.szHTMLExtension);
3595 
3596     exsExport.het = het;
3597     exsExport.szHTMLExtension = g_strdup(szExtension);
3598 
3599     outputf(_("HTML export type is now: \n" "%s\n"), aszHTMLExportType[exsExport.het]);
3600 
3601 }
3602 
3603 extern void
3604 CommandSetExportHTMLTypeBBS(char *UNUSED(sz))
3605 {
3606 
3607     SetExportHTMLType(HTML_EXPORT_TYPE_BBS, "gif");
3608 
3609 }
3610 
3611 extern void
3612 CommandSetExportHTMLTypeFibs2html(char *UNUSED(sz))
3613 {
3614 
3615     SetExportHTMLType(HTML_EXPORT_TYPE_FIBS2HTML, "gif");
3616 
3617 }
3618 
3619 extern void
3620 CommandSetExportHTMLTypeGNU(char *UNUSED(sz))
3621 {
3622 
3623     SetExportHTMLType(HTML_EXPORT_TYPE_GNU, "png");
3624 
3625 }
3626 
3627 
3628 static void
3629 SetExportHTMLCSS(const htmlexportcss hecss)
3630 {
3631 
3632     if (exsExport.hecss == hecss)
3633         return;
3634 
3635     if (exsExport.hecss == HTML_EXPORT_CSS_EXTERNAL)
3636         CommandNotImplemented(NULL);
3637 
3638     exsExport.hecss = hecss;
3639 
3640     outputf(_("CSS stylesheet for HTML export: %s\n"), gettext(aszHTMLExportCSS[hecss]));
3641 
3642 }
3643 
3644 
3645 extern void
3646 CommandSetExportHTMLCSSHead(char *UNUSED(sz))
3647 {
3648 
3649     SetExportHTMLCSS(HTML_EXPORT_CSS_HEAD);
3650 
3651 }
3652 
3653 extern void
3654 CommandSetExportHTMLCSSInline(char *UNUSED(sz))
3655 {
3656 
3657     SetExportHTMLCSS(HTML_EXPORT_CSS_INLINE);
3658 
3659 }
3660 
3661 extern void
3662 CommandSetExportHTMLCSSExternal(char *UNUSED(sz))
3663 {
3664 
3665     SetExportHTMLCSS(HTML_EXPORT_CSS_EXTERNAL);
3666 
3667 }
3668 
3669 
3670 extern void
3671 CommandSetExportHTMLPictureURL(char *sz)
3672 {
3673 
3674     if (!sz || !*sz) {
3675         outputl(_("You must specify a URL. " "See `help set export html pictureurl'."));
3676         return;
3677     }
3678 
3679     if (exsExport.szHTMLPictureURL)
3680         g_free(exsExport.szHTMLPictureURL);
3681 
3682     sz = NextToken(&sz);
3683     exsExport.szHTMLPictureURL = g_strdup(sz);
3684 
3685     outputf(_("URL for picture in HTML export is now: \n" "%s\n"), exsExport.szHTMLPictureURL);
3686 
3687 }
3688 
3689 
3690 
3691 extern void
3692 CommandSetInvertMatchEquityTable(char *sz)
3693 {
3694 
3695     int fOldInvertMET = fInvertMET;
3696 
3697     if (SetToggle("invert matchequitytable", &fInvertMET, sz,
3698                   _("Match equity table will be used inverted."),
3699                   _("Match equity table will not be use inverted.")) >= 0)
3700         UpdateSetting(&fInvertMET);
3701 
3702     if (fOldInvertMET != fInvertMET)
3703         SetInvertMET();
3704 }
3705 
3706 
3707 extern void
3708 CommandSetTutorMode(char *sz)
3709 {
3710 
3711     SetToggle("tutor-mode", &fTutor, sz, _("Warn about possibly bad play."), _("No warnings for possibly bad play."));
3712 }
3713 
3714 extern void
3715 CommandSetTutorCube(char *sz)
3716 {
3717 
3718     SetToggle("tutor-cube", &fTutorCube, sz,
3719               _("Include advice on cube decisions in tutor mode."),
3720               _("Exclude advice on cube decisions from tutor mode."));
3721 }
3722 
3723 extern void
3724 CommandSetTutorChequer(char *sz)
3725 {
3726 
3727     SetToggle("tutor-chequer", &fTutorChequer, sz,
3728               _("Include advice on chequer play in tutor mode."), _("Exclude advice on chequer play from tutor mode."));
3729 }
3730 
3731 static void
3732 _set_tutor_skill(skilltype Skill, int skillno, char *skill)
3733 {
3734 
3735     nTutorSkillCurrent = skillno;
3736     TutorSkill = Skill;
3737     outputf(_("Tutor warnings will be given for play marked `%s'.\n"), skill);
3738 }
3739 
3740 extern void
3741 CommandSetTutorSkillDoubtful(char *UNUSED(sz))
3742 {
3743 
3744     _set_tutor_skill(SKILL_DOUBTFUL, 0, _("doubtful"));
3745 }
3746 
3747 extern void
3748 CommandSetTutorSkillBad(char *UNUSED(sz))
3749 {
3750 
3751     _set_tutor_skill(SKILL_BAD, 1, _("bad"));
3752 }
3753 
3754 extern void
3755 CommandSetTutorSkillVeryBad(char *UNUSED(sz))
3756 {
3757 
3758     _set_tutor_skill(SKILL_VERYBAD, 2, _("very bad"));
3759 }
3760 
3761 /*
3762  * Sounds
3763  */
3764 
3765 /* enable/disable sounds */
3766 
3767 extern void
3768 CommandSetSoundEnable(char *sz)
3769 {
3770 
3771     SetToggle("sound enable", &fSound, sz, _("Enable sounds."), _("Disable sounds."));
3772 
3773 }
3774 
3775 /* sound system */
3776 extern void
3777 CommandSetSoundSystemCommand(char *sz)
3778 {
3779     sound_set_command(sz);
3780 }
3781 
3782 extern void
3783 CommandSetSoundSoundAgree(char *sz)
3784 {
3785 
3786     SetSoundFile(SOUND_AGREE, NextToken(&sz));
3787 
3788 }
3789 
3790 extern void
3791 CommandSetSoundSoundAnalysisFinished(char *sz)
3792 {
3793 
3794     SetSoundFile(SOUND_ANALYSIS_FINISHED, NextToken(&sz));
3795 
3796 }
3797 
3798 extern void
3799 CommandSetSoundSoundBotDance(char *sz)
3800 {
3801 
3802     SetSoundFile(SOUND_BOT_DANCE, NextToken(&sz));
3803 
3804 }
3805 
3806 extern void
3807 CommandSetSoundSoundBotWinGame(char *sz)
3808 {
3809 
3810     SetSoundFile(SOUND_BOT_WIN_GAME, NextToken(&sz));
3811 
3812 }
3813 
3814 extern void
3815 CommandSetSoundSoundBotWinMatch(char *sz)
3816 {
3817 
3818     SetSoundFile(SOUND_BOT_WIN_MATCH, NextToken(&sz));
3819 
3820 }
3821 
3822 extern void
3823 CommandSetSoundSoundChequer(char *sz)
3824 {
3825 
3826     SetSoundFile(SOUND_CHEQUER, NextToken(&sz));
3827 
3828 }
3829 
3830 extern void
3831 CommandSetSoundSoundDouble(char *sz)
3832 {
3833 
3834     SetSoundFile(SOUND_DOUBLE, NextToken(&sz));
3835 
3836 }
3837 
3838 extern void
3839 CommandSetSoundSoundDrop(char *sz)
3840 {
3841 
3842     SetSoundFile(SOUND_DROP, NextToken(&sz));
3843 
3844 }
3845 
3846 extern void
3847 CommandSetSoundSoundExit(char *sz)
3848 {
3849 
3850     SetSoundFile(SOUND_EXIT, NextToken(&sz));
3851 
3852 }
3853 
3854 extern void
3855 CommandSetSoundSoundHumanDance(char *sz)
3856 {
3857 
3858     SetSoundFile(SOUND_HUMAN_DANCE, NextToken(&sz));
3859 
3860 }
3861 
3862 extern void
3863 CommandSetSoundSoundHumanWinGame(char *sz)
3864 {
3865 
3866     SetSoundFile(SOUND_HUMAN_WIN_GAME, NextToken(&sz));
3867 
3868 }
3869 
3870 extern void
3871 CommandSetSoundSoundHumanWinMatch(char *sz)
3872 {
3873 
3874     SetSoundFile(SOUND_HUMAN_WIN_MATCH, NextToken(&sz));
3875 
3876 }
3877 
3878 extern void
3879 CommandSetSoundSoundMove(char *sz)
3880 {
3881 
3882     SetSoundFile(SOUND_MOVE, NextToken(&sz));
3883 
3884 }
3885 
3886 extern void
3887 CommandSetSoundSoundRedouble(char *sz)
3888 {
3889 
3890     SetSoundFile(SOUND_REDOUBLE, NextToken(&sz));
3891 
3892 }
3893 
3894 extern void
3895 CommandSetSoundSoundResign(char *sz)
3896 {
3897 
3898     SetSoundFile(SOUND_RESIGN, NextToken(&sz));
3899 
3900 }
3901 
3902 extern void
3903 CommandSetSoundSoundRoll(char *sz)
3904 {
3905 
3906     SetSoundFile(SOUND_ROLL, NextToken(&sz));
3907 
3908 }
3909 
3910 extern void
3911 CommandSetSoundSoundStart(char *sz)
3912 {
3913 
3914     SetSoundFile(SOUND_START, NextToken(&sz));
3915 
3916 }
3917 
3918 extern void
3919 CommandSetSoundSoundTake(char *sz)
3920 {
3921 
3922     SetSoundFile(SOUND_TAKE, NextToken(&sz));
3923 
3924 }
3925 
3926 
3927 static void
3928 SetPriority(int n)
3929 {
3930 
3931 #if defined(HAVE_SETPRIORITY)
3932     if (setpriority(PRIO_PROCESS, getpid(), n))
3933         outputerr("setpriority");
3934     else {
3935         outputf(_("Scheduling priority set to %d.\n"), n);
3936         nThreadPriority = n;
3937     }
3938 #elif WIN32
3939     /* tp - thread priority, pp - process priority */
3940     int tp = THREAD_PRIORITY_NORMAL;
3941     int pp = NORMAL_PRIORITY_CLASS;
3942     char *pch;
3943 
3944     if (n < -19) {
3945         tp = THREAD_PRIORITY_TIME_CRITICAL;
3946         pch = N_("time critical");
3947     } else if (n < -10) {
3948         tp = THREAD_PRIORITY_HIGHEST;
3949         pch = N_("highest");
3950     } else if (n < 0) {
3951         tp = THREAD_PRIORITY_ABOVE_NORMAL;
3952         pch = N_("above normal");
3953     } else if (!n) {
3954         pch = N_("normal");
3955     } else if (n < 19) {
3956         tp = THREAD_PRIORITY_BELOW_NORMAL;
3957         pch = N_("below normal");
3958     } else {
3959         /* Lowest - set to idle prioirty but raise the thread priority
3960          * to make sure it runs instead of screen savers */
3961         tp = THREAD_PRIORITY_HIGHEST;
3962         pp = IDLE_PRIORITY_CLASS;
3963         pch = N_("idle");
3964     }
3965 
3966     if (SetThreadPriority(GetCurrentThread(), tp)
3967         && SetPriorityClass(GetCurrentProcess(), pp)) {
3968         outputf(_("Priority of program set to: %s\n"), pch);
3969         nThreadPriority = n;
3970     } else
3971         outputerrf(_("Changing priority failed (trying to set priority " "%s)\n"), pch);
3972 #else
3973     (void) n;                   /* suppress unused parameter compiler warning */
3974     outputerrf(_("Priority changes are not supported on this platform.\n"));
3975 #endif                          /* HAVE_SETPRIORITY */
3976 }
3977 
3978 extern void
3979 CommandSetPriorityAboveNormal(char *UNUSED(sz))
3980 {
3981 
3982     SetPriority(-10);
3983 }
3984 
3985 extern void
3986 CommandSetPriorityBelowNormal(char *UNUSED(sz))
3987 {
3988 
3989     SetPriority(10);
3990 }
3991 
3992 extern void
3993 CommandSetPriorityHighest(char *UNUSED(sz))
3994 {
3995 
3996     SetPriority(-19);
3997 }
3998 
3999 extern void
4000 CommandSetPriorityIdle(char *UNUSED(sz))
4001 {
4002 
4003     SetPriority(19);
4004 }
4005 
4006 extern void
4007 CommandSetPriorityNice(char *sz)
4008 {
4009 
4010     int n;
4011 
4012     if ((n = ParseNumber(&sz)) < -20 || n > 20) {
4013         outputl(_("You must specify a priority between -20 and 20."));
4014         return;
4015     }
4016 
4017     SetPriority(n);
4018 }
4019 
4020 extern void
4021 CommandSetPriorityNormal(char *UNUSED(sz))
4022 {
4023 
4024     SetPriority(0);
4025 }
4026 
4027 extern void
4028 CommandSetPriorityTimeCritical(char *UNUSED(sz))
4029 {
4030 
4031     SetPriority(-20);
4032 }
4033 
4034 
4035 extern void
4036 CommandSetCheatEnable(char *sz)
4037 {
4038 
4039     SetToggle("cheat enable", &fCheat, sz,
4040               _("Allow GNU Backgammon to manipulate the dice."), _("Disallow GNU Backgammon to manipulate the dice."));
4041 
4042 }
4043 
4044 
4045 extern void
4046 CommandSetCheatPlayer(char *sz)
4047 {
4048 
4049     char *pch = NextToken(&sz), *pchCopy;
4050     int i;
4051 
4052     if (!pch) {
4053         outputl(_("You must specify a player " "(see `help set cheat player')."));
4054         return;
4055     }
4056 
4057     if ((i = ParsePlayer(pch)) == 0 || i == 1) {
4058         iPlayerSet = i;
4059 
4060         HandleCommand(sz, acSetCheatPlayer);
4061 
4062         return;
4063     }
4064 
4065     if (i == 2) {
4066         if ((pchCopy = malloc(strlen(sz) + 1)) == 0) {
4067             outputl(_("Insufficient memory."));
4068 
4069             return;
4070         }
4071 
4072         strcpy(pchCopy, sz);
4073 
4074         outputpostpone();
4075 
4076         iPlayerSet = 0;
4077         HandleCommand(sz, acSetCheatPlayer);
4078 
4079         iPlayerSet = 1;
4080         HandleCommand(pchCopy, acSetCheatPlayer);
4081 
4082         outputresume();
4083 
4084         free(pchCopy);
4085 
4086         return;
4087     }
4088 
4089     outputf(_("Unknown player `%s'\n" "(see `help set %s player').\n"), pch, szSetCommand);
4090 
4091 }
4092 
4093 extern void
4094 PrintCheatRoll(const int fPlayer, const int n)
4095 {
4096 
4097     static const char *aszNumber[21] = {
4098         N_("best"), N_("second best"), N_("third best"),
4099         N_("4th best"), N_("5th best"), N_("6th best"),
4100         N_("7th best"), N_("8th best"), N_("9th best"),
4101         N_("10th best"),
4102         N_("median"),
4103         N_("10th worst"),
4104         N_("9th worst"), N_("8th worst"), N_("7th worst"),
4105         N_("6th worst"), N_("5th worst"), N_("4th worst"),
4106         N_("third worst"), N_("second worst"), N_("worst")
4107     };
4108 
4109     outputf(_("%s will get the %s roll on each turn.\n"), ap[fPlayer].szName, gettext(aszNumber[n]));
4110 
4111 }
4112 
4113 extern void
4114 CommandSetCheatPlayerRoll(char *sz)
4115 {
4116 
4117     int n;
4118     if ((n = ParseNumber(&sz)) < 1 || n > 21) {
4119         outputl(_("You must specify a size between 1 and 21."));
4120         return;
4121     }
4122 
4123     afCheatRoll[iPlayerSet] = n - 1;
4124 
4125     PrintCheatRoll(iPlayerSet, afCheatRoll[iPlayerSet]);
4126 
4127 }
4128 
4129 extern void
4130 CommandSetExportHtmlSize(char *sz)
4131 {
4132 
4133     int n;
4134 
4135     if ((n = ParseNumber(&sz)) < 1 || n > 20) {
4136         outputl(_("You must specify a size between 1 and 20."));
4137         return;
4138     }
4139 
4140     exsExport.nHtmlSize = n;
4141 
4142     outputf(_("Size of generated HTML images is %dx%d pixels\n"), n * BOARD_WIDTH, n * BOARD_HEIGHT);
4143 
4144 
4145 }
4146 
4147 extern void
4148 CommandSetExportPNGSize(char *sz)
4149 {
4150 
4151     int n;
4152 
4153     if ((n = ParseNumber(&sz)) < 1 || n > 20) {
4154         outputl(_("You must specify a size between 1 and 20."));
4155         return;
4156     }
4157 
4158     exsExport.nPNGSize = n;
4159 
4160     outputf(_("Size of generated PNG images are %dx%d pixels\n"), n * BOARD_WIDTH, n * BOARD_HEIGHT);
4161 
4162 
4163 }
4164 
4165 static void
4166 SetVariation(const bgvariation bgvx)
4167 {
4168 
4169     bgvDefault = bgvx;
4170     CommandShowVariation(NULL);
4171 
4172     if (ms.gs != GAME_NONE)
4173         outputf(_("The current match or session is being played as `%s'.\n"), gettext(aszVariations[ms.bgv]));
4174 
4175     outputf(_("Please start a new match or session to play `%s'\n"), gettext(aszVariations[bgvDefault]));
4176 
4177 #if defined(USE_GTK)
4178     if (fX && ms.gs == GAME_NONE)
4179         ShowBoard();
4180 #endif                          /* USE_GTK */
4181 
4182 }
4183 
4184 extern void
4185 CommandSetVariation1ChequerHypergammon(char *UNUSED(sz))
4186 {
4187 
4188     SetVariation(VARIATION_HYPERGAMMON_1);
4189 
4190 }
4191 
4192 extern void
4193 CommandSetVariation2ChequerHypergammon(char *UNUSED(sz))
4194 {
4195 
4196     SetVariation(VARIATION_HYPERGAMMON_2);
4197 
4198 }
4199 
4200 extern void
4201 CommandSetVariation3ChequerHypergammon(char *UNUSED(sz))
4202 {
4203 
4204     SetVariation(VARIATION_HYPERGAMMON_3);
4205 
4206 }
4207 
4208 extern void
4209 CommandSetVariationNackgammon(char *UNUSED(sz))
4210 {
4211 
4212     SetVariation(VARIATION_NACKGAMMON);
4213 
4214 }
4215 
4216 extern void
4217 CommandSetVariationStandard(char *UNUSED(sz))
4218 {
4219 
4220     SetVariation(VARIATION_STANDARD);
4221 
4222 }
4223 
4224 
4225 extern void
4226 CommandSetGotoFirstGame(char *sz)
4227 {
4228 
4229     SetToggle("gotofirstgame", &fGotoFirstGame, sz,
4230               _("Goto first game when loading matches or sessions."),
4231               _("Goto last game when loading matches or sessions."));
4232 
4233 }
4234 
4235 
4236 static void
4237 SetEfficiency(const char *szText, char *sz, float *prX)
4238 {
4239 
4240     float r = ParseReal(&sz);
4241 
4242     if (r >= 0.0f && r <= 1.0f) {
4243         *prX = r;
4244         outputf("%s: %7.5f\n", szText, *prX);
4245     } else
4246         outputl(_("Cube efficiency must be between 0 and 1"));
4247 
4248 }
4249 
4250 extern void
4251 CommandSetCubeEfficiencyOS(char *sz)
4252 {
4253 
4254     SetEfficiency(_("Cube efficiency for one sided bearoff positions"), sz, &rOSCubeX);
4255 
4256 }
4257 
4258 extern void
4259 CommandSetCubeEfficiencyCrashed(char *sz)
4260 {
4261 
4262     SetEfficiency(_("Cube efficiency for crashed positions"), sz, &rCrashedX);
4263 
4264 }
4265 
4266 extern void
4267 CommandSetCubeEfficiencyContact(char *sz)
4268 {
4269 
4270     SetEfficiency(_("Cube efficiency for contact positions"), sz, &rContactX);
4271 
4272 }
4273 
4274 extern void
4275 CommandSetCubeEfficiencyRaceFactor(char *sz)
4276 {
4277 
4278     float r = ParseReal(&sz);
4279 
4280     if (r >= 0) {
4281         rRaceFactorX = r;
4282         outputf(_("Cube efficiency race factor set to %7.5f\n"), rRaceFactorX);
4283     } else
4284         outputl(_("Cube efficiency race factor must be larger than 0."));
4285 
4286 }
4287 
4288 extern void
4289 CommandSetCubeEfficiencyRaceMax(char *sz)
4290 {
4291 
4292     SetEfficiency(_("Cube efficiency race max"), sz, &rRaceMax);
4293 
4294 }
4295 
4296 extern void
4297 CommandSetCubeEfficiencyRaceMin(char *sz)
4298 {
4299 
4300     SetEfficiency(_("Cube efficiency race min"), sz, &rRaceMin);
4301 
4302 }
4303 
4304 extern void
4305 CommandSetCubeEfficiencyRaceCoefficient(char *sz)
4306 {
4307 
4308     float r = ParseReal(&sz);
4309 
4310     if (r >= 0) {
4311         rRaceCoefficientX = r;
4312         outputf(_("Cube efficiency race coefficient set to %7.5f\n"), rRaceCoefficientX);
4313     } else
4314         outputl(_("Cube efficiency race coefficient must be larger than 0."));
4315 
4316 }
4317 
4318 
4319 extern void
4320 CommandSetRatingOffset(char *sz)
4321 {
4322 
4323     float r = ParseReal(&sz);
4324 
4325     if (r < 0) {
4326         outputl(_("Please provide a positive rating offset\n"));
4327         return;
4328     }
4329 
4330     rRatingOffset = r;
4331 
4332     outputf(_("The rating offset for estimating absolute ratings is: %.1f\n"), rRatingOffset);
4333 
4334 }
4335 
4336 extern void
4337 CommandSetLang(char *sz)
4338 {
4339     char *result;
4340     g_free(szLang);
4341     szLang = (sz && *sz) ? g_strdup(sz) : g_strdup("system");
4342     result = SetupLanguage(szLang);
4343 
4344     if (result) {
4345 #if defined(USE_GTK)
4346         if (fX)
4347             GtkChangeLanguage();
4348         else
4349 #endif
4350             outputf(_("Locale is now '%s'\n"), result);
4351     } else
4352         outputerrf(_("Locale '%s' not supported by C library.\n"), sz);
4353 }
4354 
4355 extern void
4356 CommandSetPanelWidth(char *sz)
4357 {
4358     int n = ParseNumber(&sz);
4359 
4360     if (n < 50) {
4361         outputl(_("You must specify a number greater than 50"));
4362         return;
4363     }
4364 #if defined(USE_GTK)
4365     if (fX)
4366         SetPanelWidth(n);
4367 #endif
4368 }
4369 
4370 extern void
4371 CommandSetOutputErrorRateFactor(char *sz)
4372 {
4373 
4374     float r = ParseReal(&sz);
4375 
4376     if (r < 0) {
4377         outputl(_("Please provide a positive number\n"));
4378         return;
4379     }
4380 
4381     rErrorRateFactor = r;
4382 
4383     outputf(_("The factor used for multiplying error rates is: %.1f\n"), rErrorRateFactor);
4384 
4385 
4386 
4387 }
4388 
4389 static void
4390 SetFolder(char **folder, char *sz)
4391 {
4392     g_free(*folder);
4393     if (sz && *sz)
4394         *folder = g_strdup(sz);
4395     else
4396         *folder = NULL;
4397 }
4398 
4399 extern void
4400 CommandSetExportFolder(char *sz)
4401 {
4402     SetFolder(&default_export_folder, NextToken(&sz));
4403 }
4404 
4405 extern void
4406 CommandSetImportFolder(char *sz)
4407 {
4408     SetFolder(&default_import_folder, NextToken(&sz));
4409 }
4410 
4411 extern void
4412 CommandSetSGFFolder(char *sz)
4413 {
4414     SetFolder(&default_sgf_folder, NextToken(&sz));
4415 }
4416 
4417 static int
4418 SetXGID(char *sz)
4419 {
4420     int nMatchTo = -1;
4421     int nRules = -1;
4422     int fCrawford = 0;
4423     int anScore[2];
4424     int fMove = -1;
4425     int fTurn;
4426     unsigned int anDice[2] = { 0, 0 };
4427     int fCubeOwner = -1;
4428     int nCube = -1;
4429     int fDoubled = 0;
4430     int fJacoby = 0;
4431     matchstate msxg;
4432     TanBoard anBoard;
4433     char *posid, *matchid;
4434     char *pos;
4435 
4436     char *s = g_strdup(sz);
4437 
4438     char *c;
4439     int i;
4440     char v[9][5];
4441     int fSidesSwapped = FALSE;
4442 
4443     for (i = 0; i < 9 && (c = strrchr(s, ':')); i++) {
4444         strncpy(v[i], c + 1, 4);
4445         v[i][4] = '\0';
4446         *c = '\0';
4447     }
4448 
4449     c = strrchr(s, '=');
4450     pos = c ? c + 1 : s;
4451 
4452     if (strlen(pos) != 26) {
4453         g_free(s);
4454         return 1;
4455     }
4456 
4457     if (PositionFromXG(anBoard, pos)) {
4458         g_free(s);
4459         return 1;
4460     } else
4461         g_free(s);
4462 
4463     /* atoi(v[0]) is a maximum (money) cube value, unused in gnubg.
4464      * Special case : if it is set to 0, the position is cubeless
4465      * with gammons and backgammons counting. See msxg initialization below.
4466      * It may not be that useful though, since setting a position is typically
4467      * followed by a "hint" or "analyse" command and analysis parameters
4468      * will override that. */
4469 
4470     nMatchTo = atoi(v[1]);
4471 
4472     nRules = atoi(v[2]);
4473 
4474     if (nMatchTo > 0) {
4475         switch (nRules) {
4476         case 0:
4477             fCrawford = 0;
4478             break;
4479         case 1:
4480             fCrawford = 1;
4481             break;
4482         default:
4483             return (1);
4484         }
4485     } else {
4486         switch (nRules) {
4487         case 0:
4488             fJacoby = 0;
4489             nBeavers = 0;
4490             break;
4491         case 1:
4492             fJacoby = 1;
4493             nBeavers = 0;
4494             break;
4495         case 2:
4496             fJacoby = 0;
4497             nBeavers = 3;
4498             break;
4499         case 3:
4500             fJacoby = 1;
4501             nBeavers = 3;
4502             break;
4503         default:
4504             return 1;
4505         }
4506     }
4507 
4508     anScore[0] = atoi(v[3]);
4509     anScore[1] = atoi(v[4]);
4510 
4511     fMove = atoi(v[6]) == 1 ? 1 : 0;
4512 
4513     switch (v[5][0]) {
4514     case 'D':
4515         fTurn = !fMove;
4516         fDoubled = 1;
4517         anDice[0] = anDice[1] = 0;
4518         break;
4519     case '0':
4520     case '1':
4521     case '2':
4522     case '3':
4523     case '4':
4524     case '5':
4525     case '6':
4526         if (strlen(v[5]) != 2) {
4527             return 1;
4528         }
4529         fTurn = fMove;
4530         anDice[1] = atoi(v[5] + 1);
4531         v[5][1] = '\0';
4532         anDice[0] = atoi(v[5]);
4533         break;
4534     default:
4535         return 1;
4536     }
4537 
4538     nCube = 1 << atoi(v[8]);
4539 
4540     switch (atoi(v[7])) {
4541     case 1:
4542         fCubeOwner = 1;
4543         break;
4544     case 0:
4545         fCubeOwner = -1;
4546         break;
4547     case -1:
4548         fCubeOwner = 0;
4549     }
4550 
4551     msxg.anDice[0] = anDice[0];
4552     msxg.anDice[1] = anDice[1];
4553     msxg.fResigned = 0;
4554     msxg.fResignationDeclined = 0;
4555     msxg.fDoubled = fDoubled;
4556     msxg.cGames = 0;
4557     msxg.fMove = fMove;
4558     msxg.fTurn = fTurn;
4559     msxg.fCubeOwner = fCubeOwner;
4560     msxg.fCrawford = fCrawford;
4561     msxg.fPostCrawford = !fCrawford && (anScore[0] == nMatchTo - 1 || anScore[1] == nMatchTo - 1);
4562     msxg.nMatchTo = nMatchTo;
4563     msxg.anScore[0] = anScore[0];
4564     msxg.anScore[1] = anScore[1];
4565     msxg.nCube = nCube;
4566     msxg.bgv = bgvDefault;
4567     msxg.fCubeUse = fCubeUse;
4568     if (atoi(v[0]) == 0)
4569         msxg.fCubeUse = FALSE;
4570     msxg.fJacoby = fJacoby;
4571     msxg.gs = GAME_PLAYING;
4572 
4573     matchid = g_strdup(MatchIDFromMatchState(&msxg));
4574     CommandSetMatchID(matchid);
4575     g_free(matchid);
4576 
4577     if (!fMove) {
4578         SwapSides(anBoard);
4579         fSidesSwapped = TRUE;
4580     }
4581     posid = g_strdup(PositionID((ConstTanBoard) anBoard));
4582     CommandSetBoard(posid);
4583     g_free(posid);
4584 
4585     if ((anDice[0] == 0 && fSidesSwapped) || (anDice[0] && !fMove)) {
4586 
4587         if (GetInputYN
4588             (_
4589              ("This position has player on roll appearing on top. \nSwap players so the player on roll appears on the bottom? ")))
4590             CommandSwapPlayers(NULL);
4591     }
4592     return 0;
4593 }
4594 
4595 static char *
4596 get_base64(char *inp, char **next)
4597 {
4598     char *first, *last;
4599     int l = 0;
4600 
4601     *next = NULL;
4602     g_return_val_if_fail(inp, NULL);
4603     g_return_val_if_fail(*inp, NULL);
4604 
4605     for (first = inp; *first; first++) {
4606         if (Base64(*first) != 255)
4607             break;
4608     }
4609 
4610     if (!*first) {
4611         *next = first;
4612         return NULL;
4613     }
4614 
4615     for (last = first; *last; last++, l++) {
4616         if (Base64(*last) == 255)
4617             break;
4618     }
4619     *next = last;
4620     return g_strndup(first, l);
4621 }
4622 
4623 extern void
4624 CommandSetXGID(char *sz)
4625 {
4626     if (SetXGID(sz))
4627         outputerrf(_("Not a valid XGID '%s'"), sz);
4628 }
4629 
4630 extern void
4631 CommandSetGNUBgID(char *sz)
4632 {
4633     char *out;
4634     char *posid = NULL;
4635     char *matchid = NULL;
4636 
4637     if (SetXGID(sz) == 0)
4638         return;
4639 
4640     while (sz && *sz) {
4641         out = get_base64(sz, &sz);
4642         if (out) {
4643             if (strlen(out) == L_MATCHID) {
4644                 if (matchid)
4645                     continue;
4646                 matchid = g_strdup(out);
4647             } else if (strlen(out) == L_POSITIONID) {
4648                 if (posid)
4649                     continue;
4650                 posid = g_strdup(out);
4651             }
4652             g_free(out);
4653         }
4654         if (posid && matchid)
4655             break;
4656     }
4657     if (!posid && !matchid) {
4658         outputerrf(_("No valid IDs found"));
4659         return;
4660     }
4661     if (matchid)
4662         CommandSetMatchID(matchid);
4663     if (posid)
4664         CommandSetBoard(posid);
4665     outputf(_("Setting GNUbg ID %s:%s\n"), posid ? posid : "", matchid ? matchid : "");
4666     g_free(posid);
4667     g_free(matchid);
4668 }
4669 
4670 extern void
4671 CommandSetAutoSaveRollout(char *sz)
4672 {
4673     SetToggle("autosave rollout", &fAutoSaveRollout, sz,
4674               _("Auto save during rollouts"), _("Don't auto save during rollouts"));
4675 }
4676 
4677 extern void
4678 CommandSetAutoSaveAnalysis(char *sz)
4679 {
4680     SetToggle("autosave analysis", &fAutoSaveAnalysis, sz,
4681               _("Auto save after each analysed game"), _("Don't auto save after each analysed game"));
4682 }
4683 
4684 extern void
4685 CommandSetAutoSaveConfirmDelete(char *sz)
4686 {
4687     SetToggle("autosave confirm", &fAutoSaveConfirmDelete, sz,
4688               _("Prompt before deleting autosaves"), _("Delete autosaves automatically"));
4689 }
4690 
4691 extern void
4692 CommandSetAutoSaveTime(char *sz)
4693 {
4694     int n = ParseNumber(&sz);
4695 
4696     if (n < 1) {
4697         outputl(_("You must specify a positive autosave time in minutes"));
4698         return;
4699     }
4700     nAutoSaveTime = n;
4701 }
4702