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