X-Git-Url: http://winboard.nl/cgi-bin?p=xboard.git;a=blobdiff_plain;f=zippy.c;h=247240dbf69b525b66635094853601874ee1a895;hp=6d61ff7c8e25c0815d91fdf1c43fd10224017ce0;hb=6341a1e8f282d099affed789a69bad4660fe9cdc;hpb=91d8e5853ca580769cc130aa6ea004869118d171 diff --git a/zippy.c b/zippy.c index 6d61ff7..247240d 100644 --- a/zippy.c +++ b/zippy.c @@ -1,1153 +1,1144 @@ -/* - * zippy.c -- Implements Zippy the Pinhead chess player on ICS in XBoard - * $Id: zippy.c,v 2.2 2003/11/25 05:25:20 mann Exp $ - * - * Copyright 1991 by Digital Equipment Corporation, Maynard, - * Massachusetts. Enhancements Copyright - * 1992-2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software - * Foundation, Inc. - * - * The following terms apply to Digital Equipment Corporation's copyright - * interest in XBoard: - * ------------------------------------------------------------------------ - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and its - * documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appear in all copies and that - * both that copyright notice and this permission notice appear in - * supporting documentation, and that the name of Digital not be - * used in advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. - * - * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING - * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL - * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR - * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, - * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - * ------------------------------------------------------------------------ - * - * The following terms apply to the enhanced version of XBoard - * distributed by the Free Software Foundation: - * ------------------------------------------------------------------------ - * - * GNU XBoard is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * GNU XBoard is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - *------------------------------------------------------------------------ - ** See the file ChangeLog for a revision history. */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#if STDC_HEADERS -# include -# include -#else /* not STDC_HEADERS */ -extern char *getenv(); -# if HAVE_STRING_H -# include -# else /* not HAVE_STRING_H */ -# include -# endif /* not HAVE_STRING_H */ -#endif /* not STDC_HEADERS */ - -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif -#define HI "hlelo " - -#if HAVE_UNISTD_H -# include -#endif - -#include "common.h" -#include "zippy.h" -#include "frontend.h" -#include "backend.h" -#include "backendz.h" - -char *SendMoveToBookUser P((int nr, ChessProgramState *cps, int initial)); // [HGM] book - -static char zippyPartner[MSG_SIZ]; -static char zippyLastOpp[MSG_SIZ]; -static int zippyConsecGames; -static time_t zippyLastGameEnd; - -extern void mysrandom(unsigned int seed); -extern int myrandom(void); - -void ZippyInit() -{ - char *p; - - /* Get name of Zippy lines file */ - p = getenv("ZIPPYLINES"); - if (p != NULL) { - appData.zippyLines = p; - } - - /* Get word that Zippy thinks is insulting */ - p = getenv("ZIPPYPINHEAD"); - if (p != NULL) { - appData.zippyPinhead = p; - } - - /* What password is used for remote control? */ - p = getenv("ZIPPYPASSWORD"); - if (p != NULL) { - appData.zippyPassword = p; - } - - /* What password is used for remote commands to gnuchess? */ - p = getenv("ZIPPYPASSWORD2"); - if (p != NULL) { - appData.zippyPassword2 = p; - } - - /* Joke feature for people who try an old password */ - p = getenv("ZIPPYWRONGPASSWORD"); - if (p != NULL) { - appData.zippyWrongPassword = p; - } - - /* While testing, I want to accept challenges from only one person - (namely, my "anonymous" account), so I set an environment - variable ZIPPYACCEPTONLY. */ - p = getenv("ZIPPYACCEPTONLY"); - if ( p != NULL ) { - appData.zippyAcceptOnly = p; - } - - /* Should Zippy use "i" command? */ - /* Defaults to 1=true */ - p = getenv("ZIPPYUSEI"); - if (p != NULL) { - appData.zippyUseI = atoi(p); - } - - /* How does Zippy handle bughouse partnering? */ - /* 0=say we can't play, 1=manual partnering, 2=auto partnering */ - p = getenv("ZIPPYBUGHOUSE"); - if (p != NULL) { - appData.zippyBughouse = atoi(p); - } - - /* Does Zippy abort games with Crafty? */ - /* Defaults to 0=false */ - p = getenv("ZIPPYNOPLAYCRAFTY"); - if (p != NULL) { - appData.zippyNoplayCrafty = atoi(p); - } - - /* What ICS command does Zippy send at game end? Default: "gameend". */ - p = getenv("ZIPPYGAMEEND"); - if (p != NULL) { - appData.zippyGameEnd = p; - } - - /* What ICS command does Zippy send at game start? Default: none. */ - p = getenv("ZIPPYGAMESTART"); - if (p != NULL) { - appData.zippyGameStart = p; - } - - /* Should Zippy accept adjourns? */ - /* Defaults to 0=false */ - p = getenv("ZIPPYADJOURN"); - if (p != NULL) { - appData.zippyAdjourn = atoi(p); - } - - /* Should Zippy accept aborts? */ - /* Defaults to 0=false */ - p = getenv("ZIPPYABORT"); - if (p != NULL) { - appData.zippyAbort = atoi(p); - } - - /* Should Zippy play chess variants (besides bughouse)? */ - p = getenv("ZIPPYVARIANTS"); - if (p != NULL) { - appData.zippyVariants = p; - } - strcpy(first.variants, appData.zippyVariants); - - srandom(time(NULL)); -} - -/* - * Routines to implement Zippy talking - */ - - -char *swifties[] = { - "i acclaims:", "i admonishes:", "i advertises:", "i advises:", - "i advocates:", "i affirms:", "i alleges:", "i anathematizes:", - "i animadverts:", "i announces:", "i apostrophizes:", - "i appeals:", "i applauds:", "i approves:", "i argues:", - "i articulates:", "i asserts:", "i asseverates:", "i attests:", - "i avers:", "i avows:", "i baas:", "i babbles:", "i banters:", - "i barks:", "i bawls:", "i bays:", "i begs:", "i belches:", - "i bellows:", "i belts out:", "i berates:", "i beshrews:", - "i blabbers:", "i blabs:", "i blares:", "i blasphemes:", - "i blasts:", "i blathers:", "i bleats:", "i blithers:", - "i blubbers:", "i blurts out:", "i blusters:", "i boasts:", - "i brags:", "i brays:", "i broadcasts:", "i burbles:", - "i buzzes:", "i cachinnates:", "i cackles:", "i caterwauls:", - "i calumniates:", "i caws:", "i censures:", "i chants:", - "i chatters:", "i cheeps:", "i cheers:", "i chides:", "i chins:", - "i chirps:", "i chortles:", "i chuckles:", "i claims:", - "i clamors:", "i clucks:", "i commands:", "i commends:", - "i comments:", "i commiserates:", "i communicates:", - "i complains:", "i concludes:", "i confabulates:", "i confesses:", - "i coos:", "i coughs:", "i counsels:", "i cries:", "i croaks:", - "i crows:", "i curses:", "i daydreams:", "i debates:", - "i declaims:", "i declares:", "i delivers:", "i denounces:", - "i deposes:", "i directs:", "i discloses:", "i disparages:", - "i discourses:", "i divulges:", "i documents:", "i drawls:", - "i dreams:", "i drivels:", "i drones:", "i effuses:", - /*"i ejaculates:",*/ "i elucidates:", "i emotes:", "i endorses:", - "i enthuses:", "i entreats:", "i enunciates:", "i eulogizes:", - "i exclaims:", "i execrates:", "i exhorts:", "i expatiates:", - "i explains:", "i explicates:", "i explodes:", "i exposes:", - "i exposits:", "i expostulates: ", - "i expounds:", "i expresses:", "i extols:", - "i exults:", "i fantasizes:", "i fibs:", "i filibusters:", - "i flatters:", "i flutes:", "i fools:", "i free-associates:", - "i fulminates:", "i gabbles:", "i gabs:", "i gasps:", - "i giggles:", "i gossips:", "i gripes:", "i groans:", "i growls:", - "i grunts:", "i guesses:", "i guffaws:", "i gushes:", "i hails:", - "i hallucinates:", "i harangues:", "i harmonizes:", "i hectors:", - "i hints:", "i hisses:", "i hollers:", "i honks:", "i hoots:", - "i hosannas:", "i howls:", "i hums:", "i hypothecates:", - "i hypothesizes:", "i imagines:", "i implies:", "i implores:", - "i imprecates:", "i indicates:", "i infers:", - "i informs everyone:", "i instructs:", "i interjects:", - "i interposes:", "i intimates:", "i intones:", "i introspects:", - "i inveighs:", "i jabbers:", "i japes:", "i jests:", "i jibes:", - "i jives:", "i jokes:", "i joshes:", "i keens:", "i laments:", - "i lauds:", "i laughs:", "i lectures:", "i lies:", "i lilts:", - "i lisps:", "i maintains:", "i maledicts:", "i maunders:", - "i meows:", "i mewls:", "i mimes:", "i minces:", "i moans:", - "i moos:", "i mourns:", "i mouths:", "i mumbles:", "i murmurs:", - "i muses:", "i mutters:", "i nags:", "i natters:", "i neighs:", - "i notes:", "i nuncupates:", "i objurgates:", "i observes:", - "i offers:", "i oinks:", "i opines:", "i orates:", "i orders:", - "i panegyrizes:", "i pantomimes:", "i pants:", "i peals:", - "i peeps:", "i perorates:", "i persuades:", "i petitions:", - "i phonates:", "i pipes up:", "i pitches:", "i pleads:", - "i points out:", "i pontificates:", "i postulates:", "i praises:", - "i prates:", "i prattles:", "i preaches:", "i prescribes:", - "i prevaricates:", "i proclaims:", "i projects:", "i pronounces:", - "i proposes:", "i proscribes:", "i quacks:", "i queries:", - "i questions:", "i quips:", "i quotes:", "i rages:", "i rambles:", - "i rants:", "i raps:", "i rasps:", "i rattles:", "i raves:", - "i reacts:", "i recites:", "i recommends:", "i records:", - "i reiterates:", "i rejoins:", "i releases:", "i remarks:", - "i reminisces:", "i remonstrates:", "i repeats:", "i replies:", - "i reports:", "i reprimands:", "i reproaches:", "i reproves:", - "i resounds:", "i responds:", "i retorts:", "i reveals:", - "i reviles:", "i roars:", "i rumbles:", "i sanctions:", - "i satirizes:", "i sauces:", "i scolds:", "i screams:", - "i screeches:", "i semaphores:", "i sends:", "i sermonizes:", - "i shrieks:", "i sibilates:", "i sighs:", "i signals:", - "i signifies:", "i signs:", "i sings:", "i slurs:", "i snaps:", - "i snarls:", "i sneezes:", "i snickers:", "i sniggers:", - "i snivels:", "i snores:", "i snorts:", "i sobs:", - "i soliloquizes:", "i sounds off:", "i sounds out:", "i speaks:", - "i spews:", "i spits out:", "i splutters:", "i spoofs:", - "i spouts:", "i sputters:", "i squalls:", "i squawks:", - "i squeaks:", "i squeals:", "i stammers:", "i states:", - "i stresses:", "i stutters:", "i submits:", "i suggests:", - "i summarizes:", "i sums up:", "i swears:", "i talks:", - "i tattles:", "i teases:", "i telegraphs:", "i testifies:", - "i threatens:", "i thunders:", "i titters:", "i tongue-lashes:", - "i toots:", "i transcribes:", "i transmits:", "i trills:", - "i trumpets:", "i twaddles:", "i tweets:", "i twitters:", - "i types:", "i upbraids:", "i urges:", "i utters:", "i ventures:", - "i vibrates:", "i vilifies:", "i vituperates:", "i vocalizes:", - "i vociferates:", "i voices:", "i waffles:", "i wails:", - "i warbles:", "i warns:", "i weeps:", "i wheezes:", "i whimpers:", - "i whines:", "i whinnies:", "i whistles:", "i wisecracks:", - "i witnesses:", "i woofs:", "i writes:", "i yammers:", "i yawps:", - "i yells:", "i yelps:", "i yodels:", "i yowls:", "i zings:", -}; - -#define MAX_SPEECH 250 - -void Speak(how, whom) - char *how, *whom; -{ - static FILE *zipfile = NULL; - static struct stat zipstat; - char zipbuf[MAX_SPEECH + 1]; - static time_t lastShout = 0; - time_t now; - char *p; - int c, speechlen; - Boolean done; - - if (strcmp(how, "shout") == 0) { - now = time((time_t *) NULL); - if (now - lastShout < 1*60) return; - lastShout = now; - if (appData.zippyUseI) { - how = swifties[(unsigned) random() % - (sizeof(swifties)/sizeof(char *))]; - } - } - - if (zipfile == NULL) { - zipfile = fopen(appData.zippyLines, "r"); - if (zipfile == NULL) { - DisplayFatalError("Can't open Zippy lines file", errno, 1); - return; - } - fstat(fileno(zipfile), &zipstat); - } - - for (;;) { - fseek(zipfile, (unsigned) random() % zipstat.st_size, 0); - do { - c = getc(zipfile); - } while (c != NULLCHAR && c != '^' && c != EOF); - if (c == EOF) continue; - while ((c = getc(zipfile)) == '\n') ; - if (c == EOF) continue; - break; - } - done = FALSE; - - /* Don't use ics_prefix; we need to let FICS expand the alias i -> it, - but use the real command "i" on ICC */ - strcpy(zipbuf, how); - strcat(zipbuf, " "); - if (whom != NULL) { - strcat(zipbuf, whom); - strcat(zipbuf, " "); - } - speechlen = strlen(zipbuf); - p = zipbuf + speechlen; - - while (++speechlen < MAX_SPEECH) { - if (c == NULLCHAR || c == '^') { - *p++ = '\n'; - *p = '\0'; - SendToICS(zipbuf); - return; - } else if (c == '\n') { - *p++ = ' '; - do { - c = getc(zipfile); - } while (c == ' '); - } else if (c == EOF) { - break; - } else { - *p++ = c; - c = getc(zipfile); - } - } - /* Tried to say something too long, or junk at the end of the - file. Try something else. */ - Speak(how, whom); /* tail recursion */ -} - -int ZippyCalled(str) - char *str; -{ - return ics_handle[0] != NULLCHAR && StrCaseStr(str, ics_handle) != NULL; -} - -static char opp_name[128][32]; -static int num_opps=0; - -extern ColorClass curColor; - -static void SetCurColor( ColorClass color ) -{ - curColor = color; -} - -static void ColorizeEx( ColorClass color, int cont ) -{ - if( appData.colorize ) { - Colorize( color, cont ); - SetCurColor( color ); - } -} - -int ZippyControl(buf, i) - char *buf; - int *i; -{ - char *player, *p; - char reply[MSG_SIZ]; - -#if TRIVIA -#include "trivia.c" -#endif - - /* Possibly reject Crafty as opponent */ - if (appData.zippyPlay && appData.zippyNoplayCrafty && forwardMostMove < 4 - && looking_at(buf, i, "* kibitzes: Hello from Crafty")) - { - player = StripHighlightAndTitle(star_match[0]); - if ((gameMode == IcsPlayingWhite && - StrCaseCmp(player, gameInfo.black) == 0) || - (gameMode == IcsPlayingBlack && - StrCaseCmp(player, gameInfo.white) == 0)) { - - sprintf(reply, "%ssay This computer does not play Crafty clones\n%sabort\n%s+noplay %s\n", - ics_prefix, ics_prefix, ics_prefix, player); - SendToICS(reply); - } - return TRUE; - } - - /* If this is a computer, save the name. Then later, once the */ - /* game is really started, we will send the "computer" notice to */ - /* the engine. */ - if (appData.zippyPlay && - looking_at(buf, i, "* is in the computer list")) { - int i; - for (i=0;i= num_opps) strcpy(opp_name[num_opps++],star_match[0]); - } - if (appData.zippyPlay && looking_at(buf, i, "* * is a computer *")) { - int i; - for (i=0;i= num_opps) strcpy(opp_name[num_opps++],star_match[1]); - } - - /* Tells and says */ - if (appData.zippyPlay && - (looking_at(buf, i, "* offers to be your bughouse partner") || - looking_at(buf, i, "* tells you: [automatic message] I chose you"))) { - player = StripHighlightAndTitle(star_match[0]); - if (appData.zippyBughouse > 1 && first.initDone) { - sprintf(reply, "%spartner %s\n", ics_prefix, player); - SendToICS(reply); - if (strcmp(zippyPartner, player) != 0) { - strcpy(zippyPartner, player); - SendToProgram(reply + strlen(ics_prefix), &first); - } - } else if (appData.zippyBughouse > 0) { - sprintf(reply, "%sdecline %s\n", ics_prefix, player); - SendToICS(reply); - } else { - sprintf(reply, "%stell %s This computer cannot play bughouse\n", - ics_prefix, player); - SendToICS(reply); - } - return TRUE; - } - - if (appData.zippyPlay && appData.zippyBughouse && first.initDone && - looking_at(buf, i, "* agrees to be your partner")) { - player = StripHighlightAndTitle(star_match[0]); - sprintf(reply, "partner %s\n", player); - if (strcmp(zippyPartner, player) != 0) { - strcpy(zippyPartner, player); - SendToProgram(reply, &first); - } - return TRUE; - } - - if (appData.zippyPlay && appData.zippyBughouse && first.initDone && - (looking_at(buf, i, "are no longer *'s partner") || - looking_at(buf, i, - "* tells you: [automatic message] I'm no longer your"))) { - player = StripHighlightAndTitle(star_match[0]); - if (strcmp(zippyPartner, player) == 0) { - zippyPartner[0] = NULLCHAR; - SendToProgram("partner\n", &first); - } - return TRUE; - } - - if (appData.zippyPlay && appData.zippyBughouse && first.initDone && - (looking_at(buf, i, "no longer have a bughouse partner") || - looking_at(buf, i, "partner has disconnected") || - looking_at(buf, i, "partner has just chosen a new partner"))) { - zippyPartner[0] = NULLCHAR; - SendToProgram("partner\n", &first); - return TRUE; - } - - if (appData.zippyPlay && appData.zippyBughouse && first.initDone && - looking_at(buf, i, "* (your partner) tells you: *")) { - /* This pattern works on FICS but not ICC */ - player = StripHighlightAndTitle(star_match[0]); - if (strcmp(zippyPartner, player) != 0) { - strcpy(zippyPartner, player); - sprintf(reply, "partner %s\n", player); - SendToProgram(reply, &first); - } - sprintf(reply, "ptell %s\n", star_match[1]); - SendToProgram(reply, &first); - return TRUE; - } - - if (looking_at(buf, i, "* tells you: *") || - looking_at(buf, i, "* says: *")) - { - player = StripHighlightAndTitle(star_match[0]); - if (appData.zippyPassword[0] != NULLCHAR && - strncmp(star_match[1], appData.zippyPassword, - strlen(appData.zippyPassword)) == 0) { - p = star_match[1] + strlen(appData.zippyPassword); - while (*p == ' ') p++; - SendToICS(p); - SendToICS("\n"); - } else if (appData.zippyPassword2[0] != NULLCHAR && first.initDone && - strncmp(star_match[1], appData.zippyPassword2, - strlen(appData.zippyPassword2)) == 0) { - p = star_match[1] + strlen(appData.zippyPassword2); - while (*p == ' ') p++; - SendToProgram(p, &first); - SendToProgram("\n", &first); - } else if (appData.zippyWrongPassword[0] != NULLCHAR && - strncmp(star_match[1], appData.zippyWrongPassword, - strlen(appData.zippyWrongPassword)) == 0) { - p = star_match[1] + strlen(appData.zippyWrongPassword); - while (*p == ' ') p++; - sprintf(reply, "wrong %s\n", player); - SendToICS(reply); - } else if (appData.zippyBughouse && first.initDone && - strcmp(player, zippyPartner) == 0) { - SendToProgram("ptell ", &first); - SendToProgram(star_match[1], &first); - SendToProgram("\n", &first); - } else if (strncmp(star_match[1], HI, 6) == 0) { - extern char* programVersion; - sprintf(reply, "%stell %s %s\n", - ics_prefix, player, programVersion); - SendToICS(reply); - } else if (strncmp(star_match[1], "W0W!! ", 6) == 0) { - extern char* programVersion; - sprintf(reply, "%stell %s %s\n", ics_prefix, - player, programVersion); - SendToICS(reply); - } else if (appData.zippyTalk && (((unsigned) random() % 10) < 9)) { - if (strcmp(player, ics_handle) != 0) { - Speak("tell", player); - } - } - - ColorizeEx( ColorTell, FALSE ); - - return TRUE; - } - - if( appData.colorize && looking_at(buf, i, "* (*) seeking") ) { - ColorizeEx(ColorSeek, FALSE); - return FALSE; - } - - if (looking_at(buf, i, "* spoofs you:")) { - player = StripHighlightAndTitle(star_match[0]); - sprintf(reply, "spoofedby %s\n", player); - SendToICS(reply); - } - - return FALSE; -} - -int ZippyConverse(buf, i) - char *buf; - int *i; -{ - static char lastgreet[MSG_SIZ]; - char reply[MSG_SIZ]; - int oldi; - - /* Shouts and emotes */ - if (looking_at(buf, i, "--> * *") || - looking_at(buf, i, "* shouts: *")) - { - if (appData.zippyTalk) { - char *player = StripHighlightAndTitle(star_match[0]); - if (strcmp(player, ics_handle) == 0) { - return TRUE; - } else if (appData.zippyPinhead[0] != NULLCHAR && - StrCaseStr(star_match[1], appData.zippyPinhead) != NULL) { - sprintf(reply, "insult %s\n", player); - SendToICS(reply); - } else if (ZippyCalled(star_match[1])) { - Speak("shout", NULL); - } - } - - ColorizeEx(ColorShout, FALSE); - - return TRUE; - } - - if (looking_at(buf, i, "* kibitzes: *")) { - if (appData.zippyTalk && ((unsigned) random() % 10) < 9) { - char *player = StripHighlightAndTitle(star_match[0]); - if (strcmp(player, ics_handle) != 0) { - Speak("kibitz", NULL); - } - } - - ColorizeEx(ColorKibitz, FALSE); - - return TRUE; - } - - if (looking_at(buf, i, "* whispers: *")) { - if (appData.zippyTalk && ((unsigned) random() % 10) < 9) { - char *player = StripHighlightAndTitle(star_match[0]); - if (strcmp(player, ics_handle) != 0) { - Speak("whisper", NULL); - } - } - - ColorizeEx(ColorKibitz, FALSE); - - return TRUE; - } - - /* Messages */ - if ((looking_at(buf, i, ". * (*:*): *") && isdigit(star_match[1][0])) || - looking_at(buf, i, ". * at *:*: *")) { - if (appData.zippyTalk) { - FILE *f; - char *player = StripHighlightAndTitle(star_match[0]); - - if (strcmp(player, ics_handle) != 0) { - if (((unsigned) random() % 10) < 9) - Speak("message", player); - f = fopen("zippy.messagelog", "a"); - fprintf(f, "%s (%s:%s): %s\n", player, - star_match[1], star_match[2], star_match[3]); - fclose(f); - } - } - return TRUE; - } - - /* Channel tells */ - oldi = *i; - if (looking_at(buf, i, "*(*: *")) { - char *player; - char *channel; - if (star_match[0][0] == NULLCHAR || - strchr(star_match[0], ' ') || - strchr(star_match[1], ' ')) { - /* Oops, did not want to match this; probably a message */ - *i = oldi; - return FALSE; - } - if (appData.zippyTalk) { - player = StripHighlightAndTitle(star_match[0]); - channel = strrchr(star_match[1], '('); - if (channel == NULL) { - channel = star_match[1]; - } else { - channel++; - } - channel[strlen(channel)-1] = NULLCHAR; -#if 0 - /* Always tell to the channel (probability 90%) */ - if (strcmp(player, ics_handle) != 0 && - ((unsigned) random() % 10) < 9) { - Speak("tell", channel); - } -#else - /* Tell to the channel only if someone mentions our name */ - if (ZippyCalled(star_match[2])) { - Speak("tell", channel); - } -#endif - - ColorizeEx( atoi(channel) == 1 ? ColorChannel1 : ColorChannel, FALSE ); - } - return TRUE; - } - - if (!appData.zippyTalk) return FALSE; - - if ((looking_at(buf, i, "You have * message") && - atoi(star_match[0]) != 0) || - looking_at(buf, i, "* has left a message for you") || - looking_at(buf, i, "* just sent you a message")) { - sprintf(reply, "%smessages\n%sclearmessages *\n", - ics_prefix, ics_prefix); - SendToICS(reply); - return TRUE; - } - - if (looking_at(buf, i, "Notification: * has arrived")) { - if (((unsigned) random() % 3) == 0) { - char *player = StripHighlightAndTitle(star_match[0]); - strcpy(lastgreet, player); - sprintf(reply, "greet %s\n", player); - SendToICS(reply); - Speak("tell", player); - } - } - - if (looking_at(buf, i, "Notification: * has departed")) { - if (((unsigned) random() % 3) == 0) { - char *player = StripHighlightAndTitle(star_match[0]); - sprintf(reply, "farewell %s\n", player); - SendToICS(reply); - } - } - - if (looking_at(buf, i, "Not sent -- * is censoring you")) { - char *player = StripHighlightAndTitle(star_match[0]); - if (strcmp(player, lastgreet) == 0) { - sprintf(reply, "%s-notify %s\n", ics_prefix, player); - SendToICS(reply); - } - } - - if (looking_at(buf, i, "command is currently turned off")) { - appData.zippyUseI = 0; - } - - return FALSE; -} - -void ZippyGameStart(white, black) - char *white, *black; -{ - if (!first.initDone) { - /* Game is starting prematurely. We can't deal with this */ - SendToICS(ics_prefix); - SendToICS("abort\n"); - SendToICS(ics_prefix); - SendToICS("say Sorry, the chess program is not initialized yet.\n"); - return; - } - - if (appData.zippyGameStart[0] != NULLCHAR) { - SendToICS(appData.zippyGameStart); - SendToICS("\n"); - } -} - -void ZippyGameEnd(result, resultDetails) - ChessMove result; - char *resultDetails; -{ - if (appData.zippyAcceptOnly[0] == NULLCHAR && - appData.zippyGameEnd[0] != NULLCHAR) { - SendToICS(appData.zippyGameEnd); - SendToICS("\n"); - } - zippyLastGameEnd = time(0); -} - -/* - * Routines to implement Zippy playing chess - */ - -void ZippyHandleChallenge(srated, swild, sbase, sincrement, opponent) - char *srated, *swild, *sbase, *sincrement, *opponent; -{ - char buf[MSG_SIZ]; - int base, increment, i=0; - char rated; - VariantClass variant; - char *varname; - - rated = srated[0]; - variant = StringToVariant(swild); - varname = VariantName(variant); - base = atoi(sbase); - increment = atoi(sincrement); - - /* [DM] If icsAnalyzeEngine active we don't accept automatic games */ - if (appData.icsActive && appData.icsEngineAnalyze) return; - - /* If desired, you can insert more code here to decline matches - based on rated, variant, base, and increment, but it is - easier to use the ICS formula feature instead. */ - - if (variant == VariantLoadable) { - sprintf(buf, - "%stell %s This computer can't play wild type %s\n%sdecline %s\n", - ics_prefix, opponent, swild, ics_prefix, opponent); - SendToICS(buf); - return; - } - if (StrStr(appData.zippyVariants, varname) == NULL || - (i=first.protocolVersion) != 1 && StrStr(first.variants, varname) == NULL /* [HGM] zippyvar */ - ) { - sprintf(buf, - "%stell %s This computer can't play %s [%s], only %s\n%sdecline %s\n", - ics_prefix, opponent, swild, varname, - i ? first.variants : appData.zippyVariants, /* [HGM] zippyvar */ - ics_prefix, opponent); - SendToICS(buf); - return; - } - - /* Are we blocking match requests from all but one person? */ - if (appData.zippyAcceptOnly[0] != NULLCHAR && - StrCaseCmp(opponent, appData.zippyAcceptOnly)) { - /* Yes, and this isn't him. Ignore challenge. */ - return; - } - - /* Too many consecutive games with same opponent? If so, make him - wait until someone else has played or a timeout has elapsed. */ - if (appData.zippyMaxGames && - strcmp(opponent, zippyLastOpp) == 0 && - zippyConsecGames >= appData.zippyMaxGames && - difftime(time(0), zippyLastGameEnd) < appData.zippyReplayTimeout) { - sprintf(buf, "%stell %s Sorry, you have just played %d consecutive games against %s. To give others a chance, please wait %d seconds or until someone else has played.\n%sdecline %s\n", - ics_prefix, opponent, zippyConsecGames, ics_handle, - appData.zippyReplayTimeout, ics_prefix, opponent); - SendToICS(buf); - return; - } - - /* Engine not yet initialized or still thinking about last game? */ - if (!first.initDone || first.lastPing != first.lastPong) { - sprintf(buf, "%stell %s I'm not quite ready for a new game yet; try again soon.\n%sdecline %s\n", - ics_prefix, opponent, ics_prefix, opponent); - SendToICS(buf); - return; - } - - sprintf(buf, "%saccept %s\n", ics_prefix, opponent); - SendToICS(buf); - if (appData.zippyTalk) { - Speak("tell", opponent); - } -} - - -/* Accept matches */ -int ZippyMatch(buf, i) - char *buf; - int *i; -{ - if (looking_at(buf, i, "* * match * * requested with * (*)")) { - - ZippyHandleChallenge(star_match[0], star_match[1], - star_match[2], star_match[3], - StripHighlightAndTitle(star_match[4])); - return TRUE; - } - - /* Old FICS 0-increment form */ - if (looking_at(buf, i, "* * match * requested with * (*)")) { - - ZippyHandleChallenge(star_match[0], star_match[1], - star_match[2], "0", - StripHighlightAndTitle(star_match[3])); - return TRUE; - } - - if (looking_at(buf, i, - "* has made an alternate proposal of * * match * *.")) { - - ZippyHandleChallenge(star_match[1], star_match[2], - star_match[3], star_match[4], - StripHighlightAndTitle(star_match[0])); - return TRUE; - } - - /* FICS wild/nonstandard forms */ - if (looking_at(buf, i, "Challenge: * (*) *(*) * * * * Loaded from *")) { - /* note: star_match[2] can include "[white] " or "[black] " - before our own name. */ - if(star_match[8] == NULL || star_match[8][0] == 0) // [HGM] chessd: open-source ICS has file on next line - ZippyHandleChallenge(star_match[4], star_match[5], - star_match[6], star_match[7], StripHighlightAndTitle(star_match[0])); - else ZippyHandleChallenge(star_match[4], star_match[8], - star_match[6], star_match[7], - StripHighlightAndTitle(star_match[0])); - return TRUE; - } - - if (looking_at(buf, i, - "Challenge: * (*) *(*) * * * * : * * Loaded from *")) { - /* note: star_match[2] can include "[white] " or "[black] " - before our own name. */ - ZippyHandleChallenge(star_match[4], star_match[10], - star_match[8], star_match[9], - StripHighlightAndTitle(star_match[0])); - return TRUE; - } - - /* Regular forms */ - if (looking_at(buf, i, "Challenge: * (*) *(*) * * * * : * *") | - looking_at(buf, i, "Challenge: * (*) *(*) * * * * * *")) { - /* note: star_match[2] can include "[white] " or "[black] " - before our own name. */ - ZippyHandleChallenge(star_match[4], star_match[5], - star_match[8], star_match[9], - StripHighlightAndTitle(star_match[0])); - return TRUE; - } - - if (looking_at(buf, i, "Challenge: * (*) *(*) * * * *")) { - /* note: star_match[2] can include "[white] " or "[black] " - before our own name. */ - ZippyHandleChallenge(star_match[4], star_match[5], - star_match[6], star_match[7], - StripHighlightAndTitle(star_match[0])); - return TRUE; - } - - - if (ics_type == ICS_ICC) { // [DM] - if (looking_at(buf, i, "Your opponent offers you a draw")) { - if (first.sendDrawOffers && first.initDone) - SendToProgram("draw\n", &first); - return TRUE; - } - } else { - if (looking_at(buf, i, "offers you a draw")) { - if (first.sendDrawOffers && first.initDone) { - SendToProgram("draw\n", &first); - } - return TRUE; - } - } - - if (looking_at(buf, i, "requests that the game be aborted") || - looking_at(buf, i, "would like to abort")) { - if (appData.zippyAbort || - (gameMode == IcsPlayingWhite && whiteTimeRemaining < 0) || - (gameMode == IcsPlayingBlack && blackTimeRemaining < 0)) { - SendToICS(ics_prefix); - SendToICS("abort\n"); - } else { - SendToICS(ics_prefix); - if (appData.zippyTalk) - SendToICS("say Whoa no! I am having FUN!!\n"); - else - SendToICS("say Sorry, this computer doesn't accept aborts.\n"); - } - return TRUE; - } - - if (looking_at(buf, i, "requests adjournment") || - looking_at(buf, i, "would like to adjourn")) { - if (appData.zippyAdjourn) { - SendToICS(ics_prefix); - SendToICS("adjourn\n"); - } else { - SendToICS(ics_prefix); - if (appData.zippyTalk) - SendToICS("say Whoa no! I am having FUN playing NOW!!\n"); - else - SendToICS("say Sorry, this computer doesn't accept adjourns.\n"); - } - return TRUE; - } - - return FALSE; -} - -/* Initialize chess program with data from the first board - * of a new or resumed game. - */ -void ZippyFirstBoard(moveNum, basetime, increment) - int moveNum, basetime, increment; -{ - char buf[MSG_SIZ]; - int w, b; - char *opp = (gameMode==IcsPlayingWhite ? gameInfo.black : gameInfo.white); - Boolean sentPos = FALSE; - char *bookHit = NULL; // [HGM] book - - if (!first.initDone) { - /* Game is starting prematurely. We can't deal with this */ - SendToICS(ics_prefix); - SendToICS("abort\n"); - SendToICS(ics_prefix); - SendToICS("say Sorry, the chess program is not initialized yet.\n"); - return; - } - - /* Send the variant command if needed */ - if (gameInfo.variant != VariantNormal) { - sprintf(buf, "variant %s\n", VariantName(gameInfo.variant)); - SendToProgram(buf, &first); - } - - if ((startedFromSetupPosition && moveNum == 0) || - (!appData.getMoveList && moveNum > 0)) { - SendToProgram("force\n", &first); - SendBoard(&first, moveNum); - sentPos = TRUE; - } - - sprintf(buf, "level 0 %d %d\n", basetime, increment); - SendToProgram(buf, &first); - - /* Count consecutive games from one opponent */ - if (strcmp(opp, zippyLastOpp) == 0) { - zippyConsecGames++; - } else { - zippyConsecGames = 1; - strcpy(zippyLastOpp, opp); - } - - /* Send the "computer" command if the opponent is in the list - we've been gathering. */ - for (w=0; w= 0) ? gameInfo.whiteRating : 0; - b = (gameInfo.blackRating >= 0) ? gameInfo.blackRating : 0; - - firstMove = FALSE; - if (gameMode == IcsPlayingWhite) { - if (first.sendName) { - sprintf(buf, "name %s\n", gameInfo.black); - SendToProgram(buf, &first); - } - strcpy(ics_handle, gameInfo.white); - sprintf(buf, "rating %d %d\n", w, b); - SendToProgram(buf, &first); - if (sentPos) { - /* Position sent above, engine is in force mode */ - if (WhiteOnMove(moveNum)) { - /* Engine is on move now */ - if (first.sendTime) { - if (first.useColors) { - SendToProgram("black\n", &first); /*gnu kludge*/ - SendTimeRemaining(&first, TRUE); - SendToProgram("white\n", &first); - } else { - SendTimeRemaining(&first, TRUE); - } - } - bookHit = SendMoveToBookUser(forwardMostMove-1, &first, TRUE); // [HGM] book: send go or retrieve book move - } else { - /* Engine's opponent is on move now */ - if (first.usePlayother) { - if (first.sendTime) { - SendTimeRemaining(&first, TRUE); - } - SendToProgram("playother\n", &first); - } else { - /* Need to send a "go" after opponent moves */ - firstMove = TRUE; - } - } - } else { - /* Position not sent above, move list might be sent later */ - if (moveNum == 0) { - /* No move list coming; at start of game */ - if (first.sendTime) { - if (first.useColors) { - SendToProgram("black\n", &first); /*gnu kludge*/ - SendTimeRemaining(&first, TRUE); - SendToProgram("white\n", &first); - } else { - SendTimeRemaining(&first, TRUE); - } - } -// SendToProgram("go\n", &first); - bookHit = SendMoveToBookUser(forwardMostMove-1, &first, TRUE); // [HGM] book: send go or retrieve book move - } - } - } else if (gameMode == IcsPlayingBlack) { - if (first.sendName) { - sprintf(buf, "name %s\n", gameInfo.white); - SendToProgram(buf, &first); - } - strcpy(ics_handle, gameInfo.black); - sprintf(buf, "rating %d %d\n", b, w); - SendToProgram(buf, &first); - if (sentPos) { - /* Position sent above, engine is in force mode */ - if (!WhiteOnMove(moveNum)) { - /* Engine is on move now */ - if (first.sendTime) { - if (first.useColors) { - SendToProgram("white\n", &first); /*gnu kludge*/ - SendTimeRemaining(&first, FALSE); - SendToProgram("black\n", &first); - } else { - SendTimeRemaining(&first, FALSE); - } - } -// SendToProgram("go\n", &first); - bookHit = SendMoveToBookUser(forwardMostMove-1, &first, TRUE); // [HGM] book: send go or retrieve book move - } else { - /* Engine's opponent is on move now */ - if (first.usePlayother) { - if (first.sendTime) { - SendTimeRemaining(&first, FALSE); - } - SendToProgram("playother\n", &first); - } else { - /* Need to send a "go" after opponent moves */ - firstMove = TRUE; - } - } - } else { - /* Position not sent above, move list might be sent later */ - /* Nothing needs to be done here */ - } - } - - if(bookHit) { // [HGM] book: simulate book reply - static char bookMove[MSG_SIZ]; // a bit generous? - - programStats.depth = programStats.nodes = programStats.time = - programStats.score = programStats.got_only_move = 0; - sprintf(programStats.movelist, "%s (xbook)", bookHit); - - strcpy(bookMove, "move "); - strcat(bookMove, bookHit); - HandleMachineMove(bookMove, &first); - } -} - - -void -ZippyHoldings(white_holding, black_holding, new_piece) - char *white_holding, *black_holding, *new_piece; -{ - char buf[MSG_SIZ]; - if (gameMode != IcsPlayingBlack && gameMode != IcsPlayingWhite) return; - sprintf(buf, "holding [%s] [%s] %s\n", - white_holding, black_holding, new_piece); - SendToProgram(buf, &first); -} +/* + * zippy.c -- Implements Zippy the Pinhead chess player on ICS in XBoard + * + * Copyright 1991 by Digital Equipment Corporation, Maynard, + * Massachusetts. + * + * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006, + * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Free Software Foundation, Inc. + * + * Enhancements Copyright 2005 Alessandro Scotti + * + * The following terms apply to Digital Equipment Corporation's copyright + * interest in XBoard: + * ------------------------------------------------------------------------ + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Digital not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * ------------------------------------------------------------------------ + * + * The following terms apply to the enhanced version of XBoard + * distributed by the Free Software Foundation: + * ------------------------------------------------------------------------ + * + * GNU XBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * GNU XBoard is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + *------------------------------------------------------------------------ + ** See the file ChangeLog for a revision history. */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#if STDC_HEADERS +# include +# include +#else /* not STDC_HEADERS */ +extern char *getenv(); +# if HAVE_STRING_H +# include +# else /* not HAVE_STRING_H */ +# include +# endif /* not HAVE_STRING_H */ +#endif /* not STDC_HEADERS */ + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif +#define HI "hlelo " + +#if HAVE_UNISTD_H +# include +#endif + +#include "common.h" +#include "zippy.h" +#include "frontend.h" +#include "backend.h" +#include "backendz.h" + +char *SendMoveToBookUser P((int nr, ChessProgramState *cps, int initial)); // [HGM] book +void HandleMachineMove P((char *message, ChessProgramState *cps)); + +static char zippyPartner[MSG_SIZ]; +static char zippyLastOpp[MSG_SIZ]; +static char zippyOffender[MSG_SIZ]; // [HGM] aborter +static int zippyConsecGames; +static time_t zippyLastGameEnd; + +extern void mysrandom(unsigned int seed); +extern int myrandom(void); + +void +ZippyInit () +{ + char *p; + + /* Get name of Zippy lines file */ + p = getenv("ZIPPYLINES"); + if (p != NULL) { + appData.zippyLines = p; + } + + /* Get word that Zippy thinks is insulting */ + p = getenv("ZIPPYPINHEAD"); + if (p != NULL) { + appData.zippyPinhead = p; + } + + /* What password is used for remote control? */ + p = getenv("ZIPPYPASSWORD"); + if (p != NULL) { + appData.zippyPassword = p; + } + + /* What password is used for remote commands to gnuchess? */ + p = getenv("ZIPPYPASSWORD2"); + if (p != NULL) { + appData.zippyPassword2 = p; + } + + /* Joke feature for people who try an old password */ + p = getenv("ZIPPYWRONGPASSWORD"); + if (p != NULL) { + appData.zippyWrongPassword = p; + } + + /* While testing, I want to accept challenges from only one person + (namely, my "anonymous" account), so I set an environment + variable ZIPPYACCEPTONLY. */ + p = getenv("ZIPPYACCEPTONLY"); + if ( p != NULL ) { + appData.zippyAcceptOnly = p; + } + + /* Should Zippy use "i" command? */ + /* Defaults to 1=true */ + p = getenv("ZIPPYUSEI"); + if (p != NULL) { + appData.zippyUseI = atoi(p); + } + + /* How does Zippy handle bughouse partnering? */ + /* 0=say we can't play, 1=manual partnering, 2=auto partnering */ + p = getenv("ZIPPYBUGHOUSE"); + if (p != NULL) { + appData.zippyBughouse = atoi(p); + } + + /* Does Zippy abort games with Crafty? */ + /* Defaults to 0=false */ + p = getenv("ZIPPYNOPLAYCRAFTY"); + if (p != NULL) { + appData.zippyNoplayCrafty = atoi(p); + } + + /* What ICS command does Zippy send at game end? Default: "gameend". */ + p = getenv("ZIPPYGAMEEND"); + if (p != NULL) { + appData.zippyGameEnd = p; + } + + /* What ICS command does Zippy send at game start? Default: none. */ + p = getenv("ZIPPYGAMESTART"); + if (p != NULL) { + appData.zippyGameStart = p; + } + + /* Should Zippy accept adjourns? */ + /* Defaults to 0=false */ + p = getenv("ZIPPYADJOURN"); + if (p != NULL) { + appData.zippyAdjourn = atoi(p); + } + + /* Should Zippy accept aborts? */ + /* Defaults to 0=false */ + p = getenv("ZIPPYABORT"); + if (p != NULL) { + appData.zippyAbort = atoi(p); + } + + /* Should Zippy play chess variants (besides bughouse)? */ + p = getenv("ZIPPYVARIANTS"); + if (p != NULL) { + appData.zippyVariants = p; + } + ASSIGN(first.variants, appData.zippyVariants); + + srandom(time(NULL)); +} + +/* + * Routines to implement Zippy talking + */ + + +char *swifties[] = { + "i acclaims:", "i admonishes:", "i advertises:", "i advises:", + "i advocates:", "i affirms:", "i alleges:", "i anathematizes:", + "i animadverts:", "i announces:", "i apostrophizes:", + "i appeals:", "i applauds:", "i approves:", "i argues:", + "i articulates:", "i asserts:", "i asseverates:", "i attests:", + "i avers:", "i avows:", "i baas:", "i babbles:", "i banters:", + "i barks:", "i bawls:", "i bays:", "i begs:", "i belches:", + "i bellows:", "i belts out:", "i berates:", "i beshrews:", + "i blabbers:", "i blabs:", "i blares:", "i blasphemes:", + "i blasts:", "i blathers:", "i bleats:", "i blithers:", + "i blubbers:", "i blurts out:", "i blusters:", "i boasts:", + "i brags:", "i brays:", "i broadcasts:", "i burbles:", + "i buzzes:", "i cachinnates:", "i cackles:", "i caterwauls:", + "i calumniates:", "i caws:", "i censures:", "i chants:", + "i chatters:", "i cheeps:", "i cheers:", "i chides:", "i chins:", + "i chirps:", "i chortles:", "i chuckles:", "i claims:", + "i clamors:", "i clucks:", "i commands:", "i commends:", + "i comments:", "i commiserates:", "i communicates:", + "i complains:", "i concludes:", "i confabulates:", "i confesses:", + "i coos:", "i coughs:", "i counsels:", "i cries:", "i croaks:", + "i crows:", "i curses:", "i daydreams:", "i debates:", + "i declaims:", "i declares:", "i delivers:", "i denounces:", + "i deposes:", "i directs:", "i discloses:", "i disparages:", + "i discourses:", "i divulges:", "i documents:", "i drawls:", + "i dreams:", "i drivels:", "i drones:", "i effuses:", + /*"i ejaculates:",*/ "i elucidates:", "i emotes:", "i endorses:", + "i enthuses:", "i entreats:", "i enunciates:", "i eulogizes:", + "i exclaims:", "i execrates:", "i exhorts:", "i expatiates:", + "i explains:", "i explicates:", "i explodes:", "i exposes:", + "i exposits:", "i expostulates: ", + "i expounds:", "i expresses:", "i extols:", + "i exults:", "i fantasizes:", "i fibs:", "i filibusters:", + "i flatters:", "i flutes:", "i fools:", "i free-associates:", + "i fulminates:", "i gabbles:", "i gabs:", "i gasps:", + "i giggles:", "i gossips:", "i gripes:", "i groans:", "i growls:", + "i grunts:", "i guesses:", "i guffaws:", "i gushes:", "i hails:", + "i hallucinates:", "i harangues:", "i harmonizes:", "i hectors:", + "i hints:", "i hisses:", "i hollers:", "i honks:", "i hoots:", + "i hosannas:", "i howls:", "i hums:", "i hypothecates:", + "i hypothesizes:", "i imagines:", "i implies:", "i implores:", + "i imprecates:", "i indicates:", "i infers:", + "i informs everyone:", "i instructs:", "i interjects:", + "i interposes:", "i intimates:", "i intones:", "i introspects:", + "i inveighs:", "i jabbers:", "i japes:", "i jests:", "i jibes:", + "i jives:", "i jokes:", "i joshes:", "i keens:", "i laments:", + "i lauds:", "i laughs:", "i lectures:", "i lies:", "i lilts:", + "i lisps:", "i maintains:", "i maledicts:", "i maunders:", + "i meows:", "i mewls:", "i mimes:", "i minces:", "i moans:", + "i moos:", "i mourns:", "i mouths:", "i mumbles:", "i murmurs:", + "i muses:", "i mutters:", "i nags:", "i natters:", "i neighs:", + "i notes:", "i nuncupates:", "i objurgates:", "i observes:", + "i offers:", "i oinks:", "i opines:", "i orates:", "i orders:", + "i panegyrizes:", "i pantomimes:", "i pants:", "i peals:", + "i peeps:", "i perorates:", "i persuades:", "i petitions:", + "i phonates:", "i pipes up:", "i pitches:", "i pleads:", + "i points out:", "i pontificates:", "i postulates:", "i praises:", + "i prates:", "i prattles:", "i preaches:", "i prescribes:", + "i prevaricates:", "i proclaims:", "i projects:", "i pronounces:", + "i proposes:", "i proscribes:", "i quacks:", "i queries:", + "i questions:", "i quips:", "i quotes:", "i rages:", "i rambles:", + "i rants:", "i raps:", "i rasps:", "i rattles:", "i raves:", + "i reacts:", "i recites:", "i recommends:", "i records:", + "i reiterates:", "i rejoins:", "i releases:", "i remarks:", + "i reminisces:", "i remonstrates:", "i repeats:", "i replies:", + "i reports:", "i reprimands:", "i reproaches:", "i reproves:", + "i resounds:", "i responds:", "i retorts:", "i reveals:", + "i reviles:", "i roars:", "i rumbles:", "i sanctions:", + "i satirizes:", "i sauces:", "i scolds:", "i screams:", + "i screeches:", "i semaphores:", "i sends:", "i sermonizes:", + "i shrieks:", "i sibilates:", "i sighs:", "i signals:", + "i signifies:", "i signs:", "i sings:", "i slurs:", "i snaps:", + "i snarls:", "i sneezes:", "i snickers:", "i sniggers:", + "i snivels:", "i snores:", "i snorts:", "i sobs:", + "i soliloquizes:", "i sounds off:", "i sounds out:", "i speaks:", + "i spews:", "i spits out:", "i splutters:", "i spoofs:", + "i spouts:", "i sputters:", "i squalls:", "i squawks:", + "i squeaks:", "i squeals:", "i stammers:", "i states:", + "i stresses:", "i stutters:", "i submits:", "i suggests:", + "i summarizes:", "i sums up:", "i swears:", "i talks:", + "i tattles:", "i teases:", "i telegraphs:", "i testifies:", + "i threatens:", "i thunders:", "i titters:", "i tongue-lashes:", + "i toots:", "i transcribes:", "i transmits:", "i trills:", + "i trumpets:", "i twaddles:", "i tweets:", "i twitters:", + "i types:", "i upbraids:", "i urges:", "i utters:", "i ventures:", + "i vibrates:", "i vilifies:", "i vituperates:", "i vocalizes:", + "i vociferates:", "i voices:", "i waffles:", "i wails:", + "i warbles:", "i warns:", "i weeps:", "i wheezes:", "i whimpers:", + "i whines:", "i whinnies:", "i whistles:", "i wisecracks:", + "i witnesses:", "i woofs:", "i writes:", "i yammers:", "i yawps:", + "i yells:", "i yelps:", "i yodels:", "i yowls:", "i zings:", +}; + +#define MAX_SPEECH 250 + +void +Speak (char *how, char *whom) +{ + static FILE *zipfile = NULL; + static struct stat zipstat; + char zipbuf[MAX_SPEECH + 1]; + static time_t lastShout = 0; + time_t now; + char *p; + int c, speechlen; + + if (strcmp(how, "shout") == 0) { + now = time((time_t *) NULL); + if (now - lastShout < 1*60) return; + lastShout = now; + if (appData.zippyUseI) { + how = swifties[(unsigned) random() % + (sizeof(swifties)/sizeof(char *))]; + } + } + + if (zipfile == NULL) { + zipfile = fopen(appData.zippyLines, "r"); + if (zipfile == NULL) { + DisplayFatalError("Can't open Zippy lines file", errno, 1); + return; + } + fstat(fileno(zipfile), &zipstat); + } + + for (;;) { + fseek(zipfile, (unsigned) random() % zipstat.st_size, 0); + do { + c = getc(zipfile); + } while (c != NULLCHAR && c != '^' && c != EOF); + if (c == EOF) continue; + while ((c = getc(zipfile)) == '\n') ; + if (c == EOF) continue; + break; + } + + /* Don't use ics_prefix; we need to let FICS expand the alias i -> it, + but use the real command "i" on ICC */ + safeStrCpy(zipbuf, how, sizeof(zipbuf)/sizeof(zipbuf[0])); + strcat(zipbuf, " "); + if (whom != NULL) { + strcat(zipbuf, whom); + strcat(zipbuf, " "); + } + speechlen = strlen(zipbuf); + p = zipbuf + speechlen; + + while (++speechlen < MAX_SPEECH) { + if (c == NULLCHAR || c == '^') { + *p++ = '\n'; + *p = '\0'; + SendToICS(zipbuf); + return; + } else if (c == '\n') { + *p++ = ' '; + do { + c = getc(zipfile); + } while (c == ' '); + } else if (c == EOF) { + break; + } else { + *p++ = c; + c = getc(zipfile); + } + } + /* Tried to say something too long, or junk at the end of the + file. Try something else. */ + Speak(how, whom); /* tail recursion */ +} + +int +ZippyCalled (char *str) +{ + return ics_handle[0] != NULLCHAR && StrCaseStr(str, ics_handle) != NULL; +} + +static char opp_name[128][32]; +static int num_opps=0; + +extern ColorClass curColor; + +static void +SetCurColor (ColorClass color) +{ + curColor = color; +} + +static void +ColorizeEx (ColorClass color, int cont) +{ + if( appData.colorize ) { + Colorize( color, cont ); + SetCurColor( color ); + } +} + +int +ZippyControl (char *buf, int *i) +{ + char *player, *p; + char reply[MSG_SIZ]; + + /* Possibly reject Crafty as opponent */ + if (appData.zippyPlay && appData.zippyNoplayCrafty && forwardMostMove < 4 + && looking_at(buf, i, "* kibitzes: Hello from Crafty")) + { + player = StripHighlightAndTitle(star_match[0]); + if ((gameMode == IcsPlayingWhite && + StrCaseCmp(player, gameInfo.black) == 0) || + (gameMode == IcsPlayingBlack && + StrCaseCmp(player, gameInfo.white) == 0)) { + + snprintf(reply, MSG_SIZ, "%ssay This computer does not play Crafty clones\n%sabort\n%s+noplay %s\n", + ics_prefix, ics_prefix, ics_prefix, player); + SendToICS(reply); + } + return TRUE; + } + + /* If this is a computer, save the name. Then later, once the */ + /* game is really started, we will send the "computer" notice to */ + /* the engine. */ + if (appData.zippyPlay && + looking_at(buf, i, "* is in the computer list")) { + int i; + for (i=0;i= num_opps) safeStrCpy(opp_name[num_opps++],star_match[0], sizeof(opp_name[num_opps])/sizeof(opp_name[num_opps][0])); + } + if (appData.zippyPlay && looking_at(buf, i, "* * is a computer *")) { + int i; + for (i=0;i= num_opps) safeStrCpy(opp_name[num_opps++],star_match[1], sizeof(opp_name[num_opps])/sizeof(opp_name[num_opps][0])); + } + + /* Tells and says */ + if (appData.zippyPlay && + (looking_at(buf, i, "* offers to be your bughouse partner") || + looking_at(buf, i, "* tells you: [automatic message] I chose you"))) { + player = StripHighlightAndTitle(star_match[0]); + if (appData.zippyBughouse > 1 && first.initDone) { + snprintf(reply, MSG_SIZ,"%spartner %s\n", ics_prefix, player); + SendToICS(reply); + if (strcmp(zippyPartner, player) != 0) { + safeStrCpy(zippyPartner, player, sizeof(zippyPartner)/sizeof(zippyPartner[0])); + SendToProgram(reply + strlen(ics_prefix), &first); + } + } else if (appData.zippyBughouse > 0) { + snprintf(reply, MSG_SIZ, "%sdecline %s\n", ics_prefix, player); + SendToICS(reply); + } else { + snprintf(reply, MSG_SIZ, "%stell %s This computer cannot play bughouse\n", + ics_prefix, player); + SendToICS(reply); + } + return TRUE; + } + + if (appData.zippyPlay && appData.zippyBughouse && first.initDone && + looking_at(buf, i, "* agrees to be your partner")) { + player = StripHighlightAndTitle(star_match[0]); + snprintf(reply, MSG_SIZ, "partner %s\n", player); + if (strcmp(zippyPartner, player) != 0) { + safeStrCpy(zippyPartner, player, sizeof(zippyPartner)/sizeof(zippyPartner[0])); + SendToProgram(reply, &first); + } + return TRUE; + } + + if (appData.zippyPlay && appData.zippyBughouse && first.initDone && + (looking_at(buf, i, "are no longer *'s partner") || + looking_at(buf, i, + "* tells you: [automatic message] I'm no longer your"))) { + player = StripHighlightAndTitle(star_match[0]); + if (strcmp(zippyPartner, player) == 0) { + zippyPartner[0] = NULLCHAR; + SendToProgram("partner\n", &first); + } + return TRUE; + } + + if (appData.zippyPlay && appData.zippyBughouse && first.initDone && + (looking_at(buf, i, "no longer have a bughouse partner") || + looking_at(buf, i, "partner has disconnected") || + looking_at(buf, i, "partner has just chosen a new partner"))) { + zippyPartner[0] = NULLCHAR; + SendToProgram("partner\n", &first); + return TRUE; + } + + if (appData.zippyPlay && appData.zippyBughouse && first.initDone && + looking_at(buf, i, "* (your partner) tells you: *")) { + /* This pattern works on FICS but not ICC */ + player = StripHighlightAndTitle(star_match[0]); + if (strcmp(zippyPartner, player) != 0) { + safeStrCpy(zippyPartner, player, sizeof(zippyPartner)/sizeof(zippyPartner[0])); + snprintf(reply, MSG_SIZ, "partner %s\n", player); + SendToProgram(reply, &first); + } + snprintf(reply, MSG_SIZ, "ptell %s\n", star_match[1]); + SendToProgram(reply, &first); + return TRUE; + } + + if (looking_at(buf, i, "* tells you: *") || + looking_at(buf, i, "* says: *")) + { + player = StripHighlightAndTitle(star_match[0]); + if (appData.zippyPassword[0] != NULLCHAR && + strncmp(star_match[1], appData.zippyPassword, + strlen(appData.zippyPassword)) == 0) { + p = star_match[1] + strlen(appData.zippyPassword); + while (*p == ' ') p++; + SendToICS(p); + SendToICS("\n"); + } else if (appData.zippyPassword2[0] != NULLCHAR && first.initDone && + strncmp(star_match[1], appData.zippyPassword2, + strlen(appData.zippyPassword2)) == 0) { + p = star_match[1] + strlen(appData.zippyPassword2); + while (*p == ' ') p++; + SendToProgram(p, &first); + SendToProgram("\n", &first); + } else if (appData.zippyWrongPassword[0] != NULLCHAR && + strncmp(star_match[1], appData.zippyWrongPassword, + strlen(appData.zippyWrongPassword)) == 0) { + p = star_match[1] + strlen(appData.zippyWrongPassword); + while (*p == ' ') p++; + snprintf(reply, MSG_SIZ, "wrong %s\n", player); + SendToICS(reply); + } else if (appData.zippyBughouse && first.initDone && + strcmp(player, zippyPartner) == 0) { + SendToProgram("ptell ", &first); + SendToProgram(star_match[1], &first); + SendToProgram("\n", &first); + } else if (strncmp(star_match[1], HI, 6) == 0) { + extern char* programVersion; + snprintf(reply, MSG_SIZ, "%stell %s %s\n", + ics_prefix, player, programVersion); + SendToICS(reply); + } else if (strncmp(star_match[1], "W0W!! ", 6) == 0) { + extern char* programVersion; + snprintf(reply, MSG_SIZ, "%stell %s %s\n", ics_prefix, + player, programVersion); + SendToICS(reply); + } else if (appData.zippyTalk && (((unsigned) random() % 10) < 9)) { + if (strcmp(player, ics_handle) != 0) { + Speak("tell", player); + } + } + + ColorizeEx( ColorTell, FALSE ); + + return TRUE; + } + + if( appData.colorize && looking_at(buf, i, "* (*) seeking") ) { + ColorizeEx(ColorSeek, FALSE); + return FALSE; + } + + if (looking_at(buf, i, "* spoofs you:")) { + player = StripHighlightAndTitle(star_match[0]); + snprintf(reply, MSG_SIZ, "spoofedby %s\n", player); + SendToICS(reply); + } + + return FALSE; +} + +int +ZippyConverse(char *buf, int *i) +{ + static char lastgreet[MSG_SIZ]; + char reply[MSG_SIZ]; + int oldi; + + /* Shouts and emotes */ + if (looking_at(buf, i, "--> * *") || + looking_at(buf, i, "* shouts: *")) + { + if (appData.zippyTalk) { + char *player = StripHighlightAndTitle(star_match[0]); + if (strcmp(player, ics_handle) == 0) { + return TRUE; + } else if (appData.zippyPinhead[0] != NULLCHAR && + StrCaseStr(star_match[1], appData.zippyPinhead) != NULL) { + snprintf(reply, MSG_SIZ, "insult %s\n", player); + SendToICS(reply); + } else if (ZippyCalled(star_match[1])) { + Speak("shout", NULL); + } + } + + ColorizeEx(ColorShout, FALSE); + + return TRUE; + } + + if (looking_at(buf, i, "* kibitzes: *")) { + if (appData.zippyTalk && ((unsigned) random() % 10) < 9) { + char *player = StripHighlightAndTitle(star_match[0]); + if (strcmp(player, ics_handle) != 0) { + Speak("kibitz", NULL); + } + } + + ColorizeEx(ColorKibitz, FALSE); + + return TRUE; + } + + if (looking_at(buf, i, "* whispers: *")) { + if (appData.zippyTalk && ((unsigned) random() % 10) < 9) { + char *player = StripHighlightAndTitle(star_match[0]); + if (strcmp(player, ics_handle) != 0) { + Speak("whisper", NULL); + } + } + + ColorizeEx(ColorKibitz, FALSE); + + return TRUE; + } + + /* Messages */ + if ((looking_at(buf, i, ". * (*:*): *") && isdigit(star_match[1][0])) || + looking_at(buf, i, ". * at *:*: *")) { + if (appData.zippyTalk) { + FILE *f; + char *player = StripHighlightAndTitle(star_match[0]); + + if (strcmp(player, ics_handle) != 0) { + if (((unsigned) random() % 10) < 9) + Speak("message", player); + f = fopen("zippy.messagelog", "a"); + fprintf(f, "%s (%s:%s): %s\n", player, + star_match[1], star_match[2], star_match[3]); + fclose(f); + } + } + return TRUE; + } + + /* Channel tells */ + oldi = *i; + if (looking_at(buf, i, "*(*: *")) { + char *channel; + if (star_match[0][0] == NULLCHAR || + strchr(star_match[0], ' ') || + strchr(star_match[1], ' ')) { + /* Oops, did not want to match this; probably a message */ + *i = oldi; + return FALSE; + } + if (appData.zippyTalk) { + channel = strrchr(star_match[1], '('); + if (channel == NULL) { + channel = star_match[1]; + } else { + channel++; + } + channel[strlen(channel)-1] = NULLCHAR; + + /* Tell to the channel only if someone mentions our name */ + if (ZippyCalled(star_match[2])) { + Speak("tell", channel); + } + + ColorizeEx( atoi(channel) == 1 ? ColorChannel1 : ColorChannel, FALSE ); + } + return TRUE; + } + + if (!appData.zippyTalk) return FALSE; + + if ((looking_at(buf, i, "You have * message") && + atoi(star_match[0]) != 0) || + looking_at(buf, i, "* has left a message for you") || + looking_at(buf, i, "* just sent you a message")) { + snprintf(reply, MSG_SIZ, "%smessages\n%sclearmessages *\n", + ics_prefix, ics_prefix); + SendToICS(reply); + return TRUE; + } + + if (looking_at(buf, i, "Notification: * has arrived")) { + if (((unsigned) random() % 3) == 0) { + char *player = StripHighlightAndTitle(star_match[0]); + safeStrCpy(lastgreet, player, sizeof(lastgreet)/sizeof(lastgreet[0])); + snprintf(reply, MSG_SIZ, "greet %s\n", player); + SendToICS(reply); + Speak("tell", player); + } + } + + if (looking_at(buf, i, "Notification: * has departed")) { + if (((unsigned) random() % 3) == 0) { + char *player = StripHighlightAndTitle(star_match[0]); + snprintf(reply, MSG_SIZ, "farewell %s\n", player); + SendToICS(reply); + } + } + + if (looking_at(buf, i, "Not sent -- * is censoring you")) { + char *player = StripHighlightAndTitle(star_match[0]); + if (strcmp(player, lastgreet) == 0) { + snprintf(reply, MSG_SIZ, "%s-notify %s\n", ics_prefix, player); + SendToICS(reply); + } + } + + if (looking_at(buf, i, "command is currently turned off")) { + appData.zippyUseI = 0; + } + + return FALSE; +} + +void +ZippyGameStart (char *white, char* black) +{ + if (!first.initDone) { + /* Game is starting prematurely. We can't deal with this */ + SendToICS(ics_prefix); + SendToICS("abort\n"); + SendToICS(ics_prefix); + SendToICS("say Sorry, the chess program is not initialized yet.\n"); + return; + } + + if (appData.zippyGameStart[0] != NULLCHAR) { + SendToICS(appData.zippyGameStart); + SendToICS("\n"); + } +} + +void +ZippyGameEnd (ChessMove result, char *resultDetails) +{ + if (appData.zippyAcceptOnly[0] == NULLCHAR && + appData.zippyGameEnd[0] != NULLCHAR) { + SendToICS(appData.zippyGameEnd); + SendToICS("\n"); + } + zippyLastGameEnd = time(0); + if(forwardMostMove < appData.zippyShortGame) + safeStrCpy(zippyOffender, zippyLastOpp, sizeof(zippyOffender)/sizeof(zippyOffender[0])); + else + zippyOffender[0] = 0; // [HGM] aborter +} + +/* + * Routines to implement Zippy playing chess + */ + +void +ZippyHandleChallenge (char *srated, char *swild, char *sbase, char *sincrement, char *opponent) +{ + char buf[MSG_SIZ]; + int i=0; + VariantClass variant; + char *varname; + + variant = StringToVariant(swild); + varname = VariantName(variant); + + /* [DM] If icsAnalyzeEngine active we don't accept automatic games */ + if (appData.icsActive && appData.icsEngineAnalyze) return; + + /* If desired, you can insert more code here to decline matches + based on rated, variant, base, and increment, but it is + easier to use the ICS formula feature instead. */ + + if (variant == VariantLoadable) { + snprintf(buf, MSG_SIZ, + "%stell %s This computer can't play wild type %s\n%sdecline %s\n", + ics_prefix, opponent, swild, ics_prefix, opponent); + SendToICS(buf); + return; + } + if (StrStr(appData.zippyVariants, varname) == NULL || + ((i=first.protocolVersion) != 1 && StrStr(first.variants, varname) == NULL) /* [HGM] zippyvar */ + ) { + snprintf(buf, MSG_SIZ, + "%stell %s This computer can't play %s [%s], only %s\n%sdecline %s\n", + ics_prefix, opponent, swild, varname, + i ? first.variants : appData.zippyVariants, /* [HGM] zippyvar */ + ics_prefix, opponent); + SendToICS(buf); + return; + } + + /* Are we blocking match requests from all but one person? */ + if (appData.zippyAcceptOnly[0] != NULLCHAR && + StrCaseCmp(opponent, appData.zippyAcceptOnly)) { + /* Yes, and this isn't him. Ignore challenge. */ + return; + } + + /* Too many consecutive games with same opponent? If so, make him + wait until someone else has played or a timeout has elapsed. */ + if (appData.zippyMaxGames && + strcmp(opponent, zippyLastOpp) == 0 && + zippyConsecGames >= appData.zippyMaxGames && + difftime(time(0), zippyLastGameEnd) < appData.zippyReplayTimeout) { + snprintf(buf, MSG_SIZ, "%stell %s Sorry, you have just played %d consecutive games against %s. To give others a chance, please wait %d seconds or until someone else has played.\n%sdecline %s\n", + ics_prefix, opponent, zippyConsecGames, ics_handle, + appData.zippyReplayTimeout, ics_prefix, opponent); + SendToICS(buf); + return; + } + + /* [HGM] aborter: opponent is cheater that aborts games he doesn't like on first move. Make him wait */ + if (strcmp(opponent, zippyOffender) == 0 && + difftime(time(0), zippyLastGameEnd) < appData.zippyReplayTimeout) { + snprintf(buf, MSG_SIZ, "%stell %s Sorry, your previous game against %s was rather short. " + " It will wait %d seconds to see if a tougher opponent comes along.\n%sdecline %s\n", + ics_prefix, opponent, ics_handle, + appData.zippyReplayTimeout, ics_prefix, opponent); + SendToICS(buf); + return; + } + + /* Engine not yet initialized or still thinking about last game? */ + if (!first.initDone || first.lastPing != first.lastPong) { + snprintf(buf, MSG_SIZ, "%stell %s I'm not quite ready for a new game yet; try again soon.\n%sdecline %s\n", + ics_prefix, opponent, ics_prefix, opponent); + SendToICS(buf); + return; + } + + snprintf(buf, MSG_SIZ, "%saccept %s\n", ics_prefix, opponent); + SendToICS(buf); + if (appData.zippyTalk) { + Speak("tell", opponent); + } +} + + +/* Accept matches */ +int +ZippyMatch (char *buf, int *i) +{ + if (looking_at(buf, i, "* * match * * requested with * (*)")) { + + ZippyHandleChallenge(star_match[0], star_match[1], + star_match[2], star_match[3], + StripHighlightAndTitle(star_match[4])); + return TRUE; + } + + /* Old FICS 0-increment form */ + if (looking_at(buf, i, "* * match * requested with * (*)")) { + + ZippyHandleChallenge(star_match[0], star_match[1], + star_match[2], "0", + StripHighlightAndTitle(star_match[3])); + return TRUE; + } + + if (looking_at(buf, i, + "* has made an alternate proposal of * * match * *.")) { + + ZippyHandleChallenge(star_match[1], star_match[2], + star_match[3], star_match[4], + StripHighlightAndTitle(star_match[0])); + return TRUE; + } + + /* FICS wild/nonstandard forms */ + if (looking_at(buf, i, "Challenge: * (*) *(*) * * * * Loaded from *")) { + /* note: star_match[2] can include "[white] " or "[black] " + before our own name. */ + if(star_match[8] == NULL || star_match[8][0] == 0) // [HGM] chessd: open-source ICS has file on next line + ZippyHandleChallenge(star_match[4], star_match[5], + star_match[6], star_match[7], StripHighlightAndTitle(star_match[0])); + else ZippyHandleChallenge(star_match[4], star_match[8], + star_match[6], star_match[7], + StripHighlightAndTitle(star_match[0])); + return TRUE; + } + + if (looking_at(buf, i, + "Challenge: * (*) *(*) * * * * : * * Loaded from *")) { + /* note: star_match[2] can include "[white] " or "[black] " + before our own name. */ + ZippyHandleChallenge(star_match[4], star_match[10], + star_match[8], star_match[9], + StripHighlightAndTitle(star_match[0])); + return TRUE; + } + + /* Regular forms */ + if (looking_at(buf, i, "Challenge: * (*) *(*) * * * * : * *") | + looking_at(buf, i, "Challenge: * (*) *(*) * * * * * *")) { + /* note: star_match[2] can include "[white] " or "[black] " + before our own name. */ + ZippyHandleChallenge(star_match[4], star_match[5], + star_match[8], star_match[9], + StripHighlightAndTitle(star_match[0])); + return TRUE; + } + + if (looking_at(buf, i, "Challenge: * (*) *(*) * * * *")) { + /* note: star_match[2] can include "[white] " or "[black] " + before our own name. */ + ZippyHandleChallenge(star_match[4], star_match[5], + star_match[6], star_match[7], + StripHighlightAndTitle(star_match[0])); + return TRUE; + } + + + if (looking_at(buf, i, "Your opponent offers you a draw") || + looking_at(buf, i, "* offers you a draw")) { + if (first.sendDrawOffers && first.initDone) { + SendToProgram("draw\n", &first); + } + return TRUE; + } + + if (looking_at(buf, i, "requests that the game be aborted") || + looking_at(buf, i, "would like to abort")) { + if (appData.zippyAbort || + (gameMode == IcsPlayingWhite && whiteTimeRemaining < 0) || + (gameMode == IcsPlayingBlack && blackTimeRemaining < 0)) { + SendToICS(ics_prefix); + SendToICS("abort\n"); + } else { + SendToICS(ics_prefix); + if (appData.zippyTalk) + SendToICS("say Whoa no! I am having FUN!!\n"); + else + SendToICS("say Sorry, this computer doesn't accept aborts.\n"); + } + return TRUE; + } + + if (looking_at(buf, i, "requests adjournment") || + looking_at(buf, i, "would like to adjourn")) { + if (appData.zippyAdjourn) { + SendToICS(ics_prefix); + SendToICS("adjourn\n"); + } else { + SendToICS(ics_prefix); + if (appData.zippyTalk) + SendToICS("say Whoa no! I am having FUN playing NOW!!\n"); + else + SendToICS("say Sorry, this computer doesn't accept adjourns.\n"); + } + return TRUE; + } + + return FALSE; +} + +/* Initialize chess program with data from the first board + * of a new or resumed game. + */ +void +ZippyFirstBoard (int moveNum, int basetime, int increment) +{ + char buf[MSG_SIZ]; + int w, b; + char *opp = (gameMode==IcsPlayingWhite ? gameInfo.black : gameInfo.white); + Boolean sentPos = FALSE; + char *bookHit = NULL; // [HGM] book + + if (!first.initDone) { + /* Game is starting prematurely. We can't deal with this */ + SendToICS(ics_prefix); + SendToICS("abort\n"); + SendToICS(ics_prefix); + SendToICS("say Sorry, the chess program is not initialized yet.\n"); + return; + } + + /* Send the variant command if needed */ + if (gameInfo.variant != VariantNormal) { + snprintf(buf, MSG_SIZ, "variant %s\n", VariantName(gameInfo.variant)); + SendToProgram(buf, &first); + } + + if ((startedFromSetupPosition && moveNum == 0) || + (!appData.getMoveList && moveNum > 0)) { + SendToProgram("force\n", &first); + SendBoard(&first, moveNum); + sentPos = TRUE; + } + + snprintf(buf, MSG_SIZ, "level 0 %d %d\n", basetime, increment); + SendToProgram(buf, &first); + + /* Count consecutive games from one opponent */ + if (strcmp(opp, zippyLastOpp) == 0) { + zippyConsecGames++; + } else { + zippyConsecGames = 1; + safeStrCpy(zippyLastOpp, opp, sizeof(zippyLastOpp)/sizeof(zippyLastOpp[0])); + } + + /* Send the "computer" command if the opponent is in the list + we've been gathering. */ + for (w=0; w= 0) ? gameInfo.whiteRating : 0; + b = (gameInfo.blackRating >= 0) ? gameInfo.blackRating : 0; + + firstMove = FALSE; + if (gameMode == IcsPlayingWhite) { + if (first.sendName) { + snprintf(buf, MSG_SIZ, "name %s\n", gameInfo.black); + SendToProgram(buf, &first); + } + safeStrCpy(ics_handle, gameInfo.white, MSG_SIZ); + snprintf(buf, MSG_SIZ, "rating %d %d\n", w, b); + SendToProgram(buf, &first); + if (sentPos) { + /* Position sent above, engine is in force mode */ + if (WhiteOnMove(moveNum)) { + /* Engine is on move now */ + if (first.sendTime) { + if (first.useColors) { + SendToProgram("black\n", &first); /*gnu kludge*/ + SendTimeRemaining(&first, TRUE); + SendToProgram("white\n", &first); + } else { + SendTimeRemaining(&first, TRUE); + } + } + bookHit = SendMoveToBookUser(forwardMostMove-1, &first, TRUE); // [HGM] book: send go or retrieve book move + } else { + /* Engine's opponent is on move now */ + if (first.usePlayother) { + if (first.sendTime) { + SendTimeRemaining(&first, TRUE); + } + SendToProgram("playother\n", &first); + } else { + /* Need to send a "go" after opponent moves */ + firstMove = TRUE; + } + } + } else { + /* Position not sent above, move list might be sent later */ + if (moveNum == 0) { + /* No move list coming; at start of game */ + if (first.sendTime) { + if (first.useColors) { + SendToProgram("black\n", &first); /*gnu kludge*/ + SendTimeRemaining(&first, TRUE); + SendToProgram("white\n", &first); + } else { + SendTimeRemaining(&first, TRUE); + } + } +// SendToProgram("go\n", &first); + bookHit = SendMoveToBookUser(forwardMostMove-1, &first, TRUE); // [HGM] book: send go or retrieve book move + } + } + } else if (gameMode == IcsPlayingBlack) { + if (first.sendName) { + snprintf(buf, MSG_SIZ, "name %s\n", gameInfo.white); + SendToProgram(buf, &first); + } + safeStrCpy(ics_handle, gameInfo.black, MSG_SIZ); + snprintf(buf, MSG_SIZ, "rating %d %d\n", b, w); + SendToProgram(buf, &first); + if (sentPos) { + /* Position sent above, engine is in force mode */ + if (!WhiteOnMove(moveNum)) { + /* Engine is on move now */ + if (first.sendTime) { + if (first.useColors) { + SendToProgram("white\n", &first); /*gnu kludge*/ + SendTimeRemaining(&first, FALSE); + SendToProgram("black\n", &first); + } else { + SendTimeRemaining(&first, FALSE); + } + } +// SendToProgram("go\n", &first); + bookHit = SendMoveToBookUser(forwardMostMove-1, &first, TRUE); // [HGM] book: send go or retrieve book move + } else { + /* Engine's opponent is on move now */ + if (first.usePlayother) { + if (first.sendTime) { + SendTimeRemaining(&first, FALSE); + } + SendToProgram("playother\n", &first); + } else { + /* Need to send a "go" after opponent moves */ + firstMove = TRUE; + } + } + } else { + /* Position not sent above, move list might be sent later */ + /* Nothing needs to be done here */ + } + } + + if(bookHit) { // [HGM] book: simulate book reply + static char bookMove[MSG_SIZ]; // a bit generous? + + programStats.depth = programStats.nodes = programStats.time = + programStats.score = programStats.got_only_move = 0; + sprintf(programStats.movelist, "%s (xbook)", bookHit); + + safeStrCpy(bookMove, "move ", sizeof(bookMove)/sizeof(bookMove[0])); + strcat(bookMove, bookHit); + HandleMachineMove(bookMove, &first); + } +} + + +void +ZippyHoldings (char *white_holding, char *black_holding, char *new_piece) +{ + char buf[MSG_SIZ]; + if (gameMode != IcsPlayingBlack && gameMode != IcsPlayingWhite) return; + snprintf(buf, MSG_SIZ, "holding [%s] [%s] %s\n", + white_holding, black_holding, new_piece); + SendToProgram(buf, &first); +}