home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C!T ROM 5
/
ctrom5b.zip
/
ctrom5b
/
OS2
/
SPEL
/
PMICS
/
SRC
/
WCOMM.CC
< prev
next >
Wrap
C/C++ Source or Header
|
1994-12-17
|
34KB
|
1,059 lines
/*
PMICS -- PM interface for playing chess on internet chess server
Copyright (C) 1994 Kevin Nomura
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Author can be reached at email: chow@netcom.com
*/
#include "wcomm.hh"
#include "game.hh"
#include "pmics.hh"
#include <stdio.h>
#include <stdlib.h>
#include <ithread.hpp>
#include <icolor.hpp>
#include <ievtdata.hpp>
#include <imsgbox.hpp>
#include <ifont.hpp> // for font dialog
#include <ifontdlg.hpp>
#include <ireslib.hpp>
//#define INCL_WINMESSAGEMGR
#define INCL_WIN
#include <os2.h>
#include <strstrea.h>
#include "session.hh"
#include "engcom.hh"
#include "dlgmatch.h"
#define ICS_PROMPT "aics% "
extern EngineComm *engineComm;
extern ASession *aSession;
extern int getIntOption(IString s, int def);
extern IString getStringOption(IString s, IString def);
void icshook(IString &);
IWindowHandle hComm;
strstream commStream;
static void cancelBackspaces (IString &);
void debugmsg(char *s, IWindow *w)
{
IMessageBox mb(w);
mb.setTitle("debug msg");
mb.show(s, IMessageBox::informationIcon |
IMessageBox::yesNoCancelButton |
IMessageBox::applicationModal |
IMessageBox::moveable);
}
/**************************************************************************
* FUNCTION: constructor (class CommWindow)
*
* DESCRIPTION: Build comm window. Uses IComboBox to simulate a
* scrollable terminal window.
*
**************************************************************************/
CommWindow::CommWindow(unsigned long windowId, //Constructor for this class
IWindow *parent) :
IListBox (windowId, parent, parent, IRectangle(),
(IListBox::classDefaultStyle |
IControl::tabStop) &
~(IListBox::horizontalScroll |
IListBox::extendedSelect |
IListBox::multipleSelect))
{
IFUNCTRACE_DEVELOP();
hComm = handle(); // export commWindow handle
/******************************************
* attach IKeyboardHandler for keypresses
******************************************/
handleEventsFor(this);
/*****************************************
* attach IEditHandler to see what it does
****************************************/
/* editHandler = new CommEditHandler;
editHandler->handleEventsFor(this);*/
/**************************************
* attach IHandler for general events
**************************************/
msgHandler = new CommMsgHandler(this);
msgHandler->handleEventsFor(this);
commFilter = new ACommFilterStyle12;
localecho = getIntOption("localecho", 0) != 0;
// setColor(IEntryField::background, IColor(0xff,0xff,0xcc));
setFont(IFont(getStringOption("commfont", "System VIO"),
getIntOption("commfontsize", 14)));
show();
} /* end PmicsWindow :: PmicsWindow(...) */
Boolean CommWindow::key (IKeyboardEvent &evt)
{
char c,s[2];
int i;
if (evt.isUpTransition()) {
return false;
}
IFUNCTRACE_DEVELOP(); // bypassed on up transition
/********************************************************************
* keyhandler screws up for control chars. they don't show up
* as character events, but only as scancode events: and who wants
* to fool with scancodes? we hafta drop down to PM and dig the char
* out of the event data, sigh.
********************************************************************/
if (evt.isCtrlDown()) {
ITRACE_DEVELOP("control is down");
if (evt.isVirtual() && evt.virtualKey() == IKeyboardEvent::ctrl)
return false; // the ctrl key itself
c = IEventData(evt.parameter2()).char1();
ITRACE_DEVELOP("control pressed, data is: " + IString(c)+IString((int)c));
if (c>='a' && c<='z')
c = c - 'a' + 1;
else if (c == '-') c = 31;
else if (c == ']') c = 29;
else if (c == '[') c = 27;
else c = 127;
s[0] = c;
s[1] = 0;
for (i = evt.isRepeat() ? evt.repeatCount() : 1; i; i--)
aSession->write(s);
}
if (evt.isVirtual()) {
ITRACE_DEVELOP("vkey: " + IString((unsigned short)(evt.virtualKey())) +
" *" + IString(evt.repeatCount()));
switch(evt.virtualKey()) {
case IKeyboardEvent::backSpace:
c = (bs2del) ? 127 : 8;
ITRACE_DEVELOP("BS: deleting last character with " + IString((int)c));
s[0] = c;
s[1] = 0;
for (i = evt.isRepeat() ? evt.repeatCount() : 1; i; i--)
aSession->write(s);
return true;
case IKeyboardEvent::newLine:
c = (cr2lf) ? 10 : 13;
ITRACE_DEVELOP("CR: newLine maps to " + IString((int)c));
s[0] = c;
s[1] = 0;
for (i = evt.isRepeat() ? evt.repeatCount() : 1; i; i--)
aSession->write(s);
return true;
}
//return false; // use default semantics for arrow keys, etc.
// need fall thru for chars
}
if (evt.isCharacter()) {
ITRACE_DEVELOP("key: " + IString((unsigned short)(evt.character())));
if (evt.isRepeat() || evt.repeatCount() > 0)
ITRACE_DEVELOP("repeatCount = "+IString(evt.repeatCount())+
"isRepeat = "+IString(evt.repeatCount()));
c = evt.character();
if (evt.isCtrlDown()) {
ITRACE_DEVELOP(" control: " + IString(c) + "=" + IString((int)c));
if (c>='a' && c<='z')
c = c - 'a' + 1;
}
/*if (c == '\r') {
c = '\n';
ITRACE_DEVELOP("<CR> -> <LF>");
}*/
s[0] = c;
s[1] = 0;
for (i = evt.isRepeat() ? evt.repeatCount() : 1; i; i--)
aSession->write(s);
timerTick(0); // reset idle counter
/********************************************************
* implement local echo
********************************************************/
if (localecho) {
int i = count() - 1;
setItemText(i, itemText(i) + IString(c));
}
return true; // suppress listbox jump to line with first letter
}
return false;
}
/**************************************************************************
* FUNCTION: lookForChallenge (class CommWindow)
*
* DESCRIPTION: Recognize a match request from another ICS player, and
* pop up a requester that notifies the user and lets them accept,
* reject or ignore the match request. Example challenge line:
*
* Challenge: DaveS (2068) [white] woof (1813) [un]rated blitz|wild(n)|standard 3 12 [5 0]
*
**************************************************************************/
void CommWindow::lookForChallenge (IString &line)
{
int i, oppName, wildType, firstClock, secondClock;
extern IWindow *mainWin;
Boolean isRated, isWhite, isBlack;
if (line.subString(1,10) != "Challenge:")
return;
// parse as blank-separated tokens, starting after "Challenge:"
i = 2;
isWhite = isBlack = isRated = false;
wildType = 0;
oppName = i;
i++; i++; // consume opponent name and rating
if (line.word(i)[1] == '[') { // color specification
if (line.word(i) == "[white]")
isWhite = true;
else if (line.word(i) == "[black]")
isBlack = true;
i++; // consume color specification
}
i++; i++; // consume my name and rating
isRated = (line.word(i) == "rated");
i++; // consume rated specification
if (line.word(i).subString(1,4) == "wild") {
sscanf(line.word(i), "wild(%d)", &wildType);
}
i++; // consume blitz/standard/wild specification
firstClock = i;
i++; i++; // consume 1st time specification
secondClock = 0;
if (line.numWords() >= i+1) {
secondClock = i;
i++; i++; // consume odds time specification
}
ITRACE_DEVELOP("challenge: <"+line+">");
AMatchDialog *dw = new AMatchDialog(IWindow::desktopWindow(),
mainWin,
this,
line.words(oppName,2),
isRated,
isWhite,
isBlack,
wildType,
line.words(firstClock,2),
secondClock ? line.words(secondClock,2) : IString(""));
}
/**************************************************************************
* FUNCTION: fontDialog (class CommWindow)
*
* DESCRIPTION: Let the user select a new text font for the comm window.
*
**************************************************************************/
void CommWindow::fontDialog()
{
if (0)
{
// rated blitz
IString s = "Challenge: caesar (1669) woof (1680) rated blitz 3 12";
lookForChallenge(s);
// unrated wild
s = "Challenge: caesar (1669) woof (1680) unrated wild(5) 3 12";
lookForChallenge(s);
// rated wild 14, white, with time odds
s = "Challenge: caesar (1669) [black] woof (1680) rated wild(14) 3 12 1 0";
lookForChallenge(s);
}
IFont curfont(this);
IFontDialog::Settings fsettings(&curfont);
IFontDialog fd(IWindow::desktopWindow(),IWindow::desktopWindow(), fsettings);
if (fd.pressedOK())
setFont(curfont);
}
/**************************************************************************
* FUNCTION: timerTick (class CommWindow)
*
* DESCRIPTION: Send a key to the UNIX host every 3 minutes to prevent
* idle detection. Driven by 1-second interval timer tick (we share
* the timer in PmicsWindow).
*
* ================ MAKE CONFIGURABLE =======================
*
**************************************************************************/
void CommWindow::timerTick(int setCount)
{
static int count = 0;
if (setCount >= 0)
count = setCount;
else
count++;
if ((count > 0) && (count % 360 == 0)) {
ITRACE_DEVELOP("CommWindow::timerTick send keepalive char, count="+
IString(count));
aSession->write(" ");
}
}
/**************************************************************************
* FUNCTION: edit (class CommEditHandler)
*
* DESCRIPTION: This handler is supposed to intercept editing keys
* inside the IComboBox.
*
**************************************************************************/
Boolean CommEditHandler :: edit (IControlEvent &evt)
{
IFUNCTRACE_DEVELOP();
char s[2], c;
ITRACE_DEVELOP(IString("char1: ") +
IString((unsigned short)(evt.parameter1().char1())) +
IString(" char2: ") +
IString((unsigned short)(evt.parameter1().char2())) +
IString(" char3: ") +
IString((unsigned short)(evt.parameter1().char3())) +
IString(" char4: ") +
IString((unsigned short)(evt.parameter1().char4())));
ITRACE_DEVELOP(IString("char1: ") +
IString((unsigned short)(evt.parameter2().char1())) +
IString(" char2: ") +
IString((unsigned short)(evt.parameter2().char2())) +
IString(" char3: ") +
IString((unsigned short)(evt.parameter2().char3())) +
IString(" char4: ") +
IString((unsigned short)(evt.parameter2().char4())) +
IString(" *") +
IString((unsigned short)(evt.parameter1().char3())));
if (!(evt.parameter1() & KC_KEYUP)) {
ITRACE_DEVELOP("keydown event");
}
if ((evt.parameter1() & KC_CTRL)) {
ITRACE_DEVELOP("ctrl event");
}
return false;
}
/**************************************************************************
* FUNCTION: dispatchHandlerEvent (class CommMsgHandler)
*
* DESCRIPTION: handler for general window messages
*
* MESSAGES: MSG_COM_IN - arbitrary-sized block of incoming data
* MSG_COM_FONT - user requested to change comm window font
*
**************************************************************************/
Boolean CommMsgHandler::dispatchHandlerEvent (IEvent &evt)
{
// IFUNCTRACE_DEVELOP();
CommWindow *cwin = (CommWindow *)evt.window();
switch (evt.eventId()) {
case MSG_COM_IN:
/**************************************************************************
* Blocks of incoming data are relayed here from the session object for
* processing. (1) Display the data in the comm window. The comm window
* works in terms of lines so we must break the data apart at line
* boundaries, and also know when the last line of the previous block
* is unfinished and needs to be continued. (2) Build a line stream.
* Run the resulting complete lines through a filter which looks for
* challenges.
*************************************************************************/
{
char buf[4000];
static IString line,prevline;
static Boolean continued = false; // if last line not terminated
static Boolean filterNextPrompt = false; // cosmetics
int linelen, peekc;
while(1) {
commStream.get(buf, sizeof(buf));
if (commStream.fail()) break;
line = IString(buf);
if ((peekc = commStream.peek()) == '\n')
commStream.get();
// strip trailing CR (getline broke at LF of CRLF pair)
line.strip("\n\r");
// line.strip("\r");
ITRACE_DEVELOP("MSG_COM_IN <"+line+">");
/********************************************************
* if last line was not terminated, append this line to it
********************************************************/
// cwin->setCursorAt(cwin->textLength());
if (continued) {
CommWindow::Cursor cur(*commWindow, CommWindow::Cursor::allItems);
cur.setToLast();
line = prevline + line;
ITRACE_DEVELOP("Continuing previous line: now <"+line+">");
continued = (commStream.peek() == EOF && peekc != '\n');
cancelBackspaces(line);
if (line.subString(1,4) != "<12>")
cwin->replaceAt(line, cur);
}
else {
/**************************************************
* otherwise add this line as a new line at the end
**************************************************/
if (line.subString(1,4) != "<12>")
cwin->addAsLast(line);
}
if (filterNextPrompt) {
// if hit, delete the line. else, clear the bit if line is not
// a prefix of the prompt, meaning prompt did not follow the move
// string for some reason.
if (line == ICS_PROMPT) {
cwin->remove(cwin->count() - 1);
filterNextPrompt = false;
}
else if (IString(ICS_PROMPT).indexOf(line) != 1)
filterNextPrompt = false;
}
/**************************************************************
* predict if this line is continued, and if not, run through
* move capture filter
**************************************************************/
if (! ((commStream.peek() == EOF && peekc != '\n'))) {
if (cwin->commFilter->filter(line)) {
/* cwin->remove(cwin->count() - 1);*/
filterNextPrompt = true;
}
else
cwin->lookForChallenge(line);
}
// could add a hook here to login to a dialup system
//icshook(line);
prevline = line;
}
continued = (commStream.peek() == EOF && peekc != '\n');
/***************************************************************
* manage number of lines in listbox and the cursor position
***************************************************************/
if (cwin->count() > 300) {
// first get down to 300 for sure
while (cwin->remove(0) > 300) ;
// now delete 10% more (to prevent thrashing on continuous input)
for (int i=0; i<30; i++)
cwin->remove(0);
}
/**************************************************************
* scroll listbox to bottom by setting 'top' to the last line
**************************************************************/
cwin->setTop(cwin->count());
evt.setResult(0);
return true;
}
break;
case MSG_COM_FONT:
ITRACE_DEVELOP("comm window: font message has arrived");
cwin->fontDialog();
return true;
}
return false;
}
/**************************************************************************
* FUNCTION: filter (class ACommFilterStyle12)
*
* DESCRIPTION: parse style 12 move messages from ICS
* This notifies us that a move has been made in the game, and new
* status information is available (clocks, etc). The information
* is digested and posted to the stat and board windows for display.
*
* ics% help style12
* A new style 12 now exists. It has all the advantages of style 8 and
* style 10. Furthermore, style 12 inhibits the messages "OBSERVATION
* REPORT" and "Game 7 (Quimbee vs. Darooha)". (Actually, I may make
* this a feature of terse mode. In any event, don't depend on those
* messages.)
*
* The data is all on one line: Here is an example:
*
* <12> rnbqkb-r pppppppp -----n-- -------- ----P--- -------- PPPPKPPP RNBQ-BNR B -
* 1 0 0 1 1 0 7 Quimbee Darooha 1 2 12 39 39 119 122 2 K/e1-e2 (0:06) Ke2
*
* This always begins on a new line, and there are always exactly 30
* non-empty fields separated by blanks. They are:
*
* - The string "<12>" to identify this line.
* - eight fields representing the board position. The first one is file 8,
* then file 7, etc, regardless of who's move it is.
* - color whose turn it is to move ("B" or "W")
* - -1 if the previous move was NOT a double pawn push,
* otherwise the file (numbered 0--7 for a--h) in which
* the double push was made
* - can white still castle short? (0=no, 1=yes)
* - can white still castle long?
* - can black still castle short?
* - can black still castle long?
* - the number of moves made since the last irreversible move.
* (0 if last move was irreversible. If this is >= 100, the game
* can be declared a draw due to the 50 move rule.)
* - The game number
* - White's name
* - Black's name
* - is it my turn to move in this game? (1=yes, -1=opponent's move,
* 0=observing)
* - initial time (in seconds) of the match
* - increment of the match
* - white strength
* - black strength
* - white's remaining time
* - black's remaining time
* - the number of the move about to be made
* (standard chess numbering -- White's and Black's first moves
* are both 1, etc.)
* - verbose coordinate notation for the previous move ("none" if
* there were none)
* - time taken to make previous move "(min:sec)".
* - pretty notation for the previous move ("none" if there is none)
*
* New fields may be added to the end in the future, so programs should
* parse from left to right.
**************************************************************************/
Boolean ACommFilterStyle12::filter(IString &line)
{
int gameNum, moveNum, timeW, timeB, lastMoveTime, clockRun;
char playerW[17], playerB[17];
IString moveAlg, engMove;
struct statData {
char onMove;
int wClock, bClock, gameNum;
char wName[32], bName[32], move[32];
} *p;
char *pfld[30], *token;
int min, sec, whosemove;
enum {S12_ID=0, S12_RANK1, S12_RANK2, S12_RANK3, S12_RANK4, S12_RANK5,
S12_RANK6, S12_RANK7, S12_RANK8, S12_ONMOVE, S12_ENPASSANT,
S12_W00, S12_W000, S12_B00, S12_B000, S12_DRAWCTR, S12_GAMENUM,
S12_WNAME, S12_BNAME, S12_WHOSEMOVE, S12_INITCLOCK, S12_INCR,
S12_WMATERIAL, S12_BMATERIAL, S12_WTIME, S12_BTIME,
S12_MOVENUM, S12_MOVERAW, S12_MOVETIME, S12_MOVEALG};
AGame *currentGame;
static int failCount = 0;
IFUNCTRACE_DEVELOP();
if (line.subString(1,4) != "<12>")
return false;
ITRACE_DEVELOP(line);
/************************************************************************
* tokenize line into blank-separated fields; verify they're all present
************************************************************************/
token = strtok((char *)line, " ");
for (int i = 0; i < 30; i++) {
if (token == NULL) {
// this has been happening lately so we'll recover by issuing
// a refresh command.
ITRACE_DEVELOP("error in style12: line ends too soon i=" + IString(i));
if (++failCount < 3)
aSession->write("refresh\nrefresh\n");
return false; // error! recovery: ignore (should warn user)
}
pfld[i] = token;
token = strtok((char *)NULL, " "); // dont care about tokens after 30th
}
sscanf(pfld[S12_GAMENUM], "%3d", &gameNum);
sscanf(pfld[S12_WNAME], "%16s", &playerW);
sscanf(pfld[S12_BNAME], "%16s", &playerB);
sscanf(pfld[S12_MOVENUM], "%3d", &moveNum);
sscanf(pfld[S12_WTIME], "%5d", &timeW);
sscanf(pfld[S12_BTIME], "%5d", &timeB);
sscanf(pfld[S12_MOVETIME], "(%d:%d)", &min, &sec);
sscanf(pfld[S12_WHOSEMOVE], "%d", &whosemove);
lastMoveTime = min*60+sec;
clockRun = TRUE;
moveAlg = IString(pfld[S12_MOVEALG]);
/**********************************
* post stat window with new info
**********************************/
p = new struct statData;
p->wClock = timeW;
p->bClock = timeB;
p->onMove = pfld[S12_ONMOVE][0];
strcpy(p->wName, playerW);
strcpy(p->bName, playerB);
p->gameNum = gameNum;
if (pfld[S12_ONMOVE][0] == 'B')
strcpy(p->move, IString(moveNum) + ". " + moveAlg);
else
strcpy(p->move, IString(moveNum-1) + "... " + moveAlg);
hMain.postEvent(MSG_STAT_UPDATE, (void *)p);
hMain.postEvent(pfld[S12_ONMOVE][0] == 'W' ?
MSG_STAT_WHITE_ONMOVE :
MSG_STAT_BLACK_ONMOVE,
(ULONG) whosemove);
/*************************************************************************
* send moves of active game to engine
* reformat as coordinate notation with promotion piece at end, e.g. a7b8q
*************************************************************************/
engMove = IString(pfld[S12_MOVERAW]);
if (whosemove == 1) {
if (engMove[2] == '/') { // P/e2-e4=Q (castling is sent verbatim)
int eqpos;
engMove.remove(1,2);
engMove.remove(3,1);
engMove.remove(5);
if (eqpos = moveAlg.indexOf('=')) { // promotion indicator
engMove += moveAlg.subString(eqpos+1,1).lowerCase();
}
}
engineComm->sendCommand(engMove);
}
currentGame = AGame::current();
for (int rank=0; rank<8; rank++) {
for (int file=0; file<8; file++) {
currentGame->setPiece(file, rank,
AGame::toPiece(pfld[S12_RANK8 - rank][file]));
}
}
/********************************************************
* if initial position, initialize some state objects
********************************************************/
if (moveNum==1 && strcmp("W", pfld[S12_ONMOVE]) == 0) {
ITRACE_DEVELOP("New game starting. whosemove=" + IString(whosemove));
if (whosemove == 1) // my move so put white at bottom
hBoard.postEvent(MSG_BOARD_WHITE_AT_BOTTOM);
else if (whosemove == -1) // my opponent's move so put black at bottom
hBoard.postEvent(MSG_BOARD_WHITE_AT_TOP);
else // observing only. put white at bottom.
hBoard.postEvent(MSG_BOARD_WHITE_AT_BOTTOM);
engineComm->sendCommand("new");
}
else
hBoard.postEvent(MSG_BOARD_UPDATE);
failCount = 0;
return true;
}
static void cancelBackspaces (IString &s)
{
int i;
while ((i = s.indexOf('\b')) > 1) {
s.remove(i-1,2); // cancel BS and previous char
}
}
void icshook (IString &s)
{
static int next = 0;
static char *script[] = {
"help abort",
"help abuse",
"help abusers",
"help accept",
"help ACM",
"help addresses",
"help adjourn",
"help adjudicate",
"help admins",
"help alias",
"help allobservers",
"help assess",
"help atmosphere",
"help backward",
"help bell",
"help best",
"help bugs",
"help channel",
"help clearmessages",
"help cls",
"help computers",
"help courtesyabort",
"help credits",
"help date",
"help decline",
"help definitions",
"help doah",
"help draw",
"help eco",
"help examine",
"help exit",
"help filters",
"help finger",
"help flag",
"help flip",
"help formula",
"help fortune",
"help forward",
"help ftp-hints",
"help games",
"help GIICS",
"help GMs",
"help gnusurf",
"help goodpasswd",
"help handle",
"help help",
"help history",
"help i",
"help ICS",
"help ICS-InTheNews",
"help inchannel",
"help index",
"help InetChessLibrary",
"help interfaces",
"help intro1",
"help intro10",
"help intro11",
"help intro2",
"help intro3",
"help intro4",
"help intro5",
"help intro6",
"help intro7",
"help intro8",
"help intro9",
"help Isbjoern",
"help kibitz",
"help lag",
"help lagflag",
"help lhistory",
"help LinaresRoundup",
"help lists",
"help llogons",
"help logons",
"help mailhelp",
"help mailoldmoves",
"help mailstored",
"help match",
"help messages",
"help mexamine",
"help minus",
"help mood",
"help moretime",
"help motd",
"help moves",
"help muzzle",
"help new",
"help notation",
"help notify",
"help nuke",
"help observe",
"help odds-games",
"help oldmoves",
"help open",
"help password",
"help PCA-candidates",
"help pending",
"help people",
"help players",
"help plus",
"help programmers",
"help promote",
"help quit",
"help quota",
"help rank",
"help rated",
"help ratings",
"help records",
"help refresh",
"help refresh",
"help registration",
"help registration",
"help resign",
"help revert",
"help rules",
"help say",
"help server",
"help set",
"help shout",
"help smoves",
"help splay-tree",
"help sposition",
"help sshout",
"help statistics",
"help stored",
"help style",
"help style",
"help style10",
"help style12",
"help suggestions",
"help takeback",
"help team-games",
"help tell",
"help terse-mode",
"help time",
"help tournaments",
"help Tourny-Rishi",
"help TournyWC",
"help unexamine",
"help upstatistics",
"help vars",
"help vars",
"help whisper",
"help who",
"help who1",
"help who2",
"help wild",
"help wild10",
"help wild11",
"help wild12",
"help wild13",
"help wild14",
"help wild5",
"help wild6",
"help wild7",
"help wild8",
"help wild9",
"help xtell",
"help znotl",
""};
if (next == -1) return;
if (script[next][0] == 0) {next = -1; return;}
if (s == "aics% ") {
aSession->write(IString(script[next]) + "\n");
next++;
}
return;
}
/**************************************************************************
* FUNCTION: constructor (class AMatchDialog)
*
* DESCRIPTION:
*
**************************************************************************/
AMatchDialog:: AMatchDialog(IWindow *parent, // ctor for this class
IWindow *owner,
IWindow *commWin,
IString cName,
int cIsRated,
int cWildType,
int cIsWhite,
int cIsBlack,
IString cClock,
IString cOddsClock) :
IFrameWindow (DID_MATCH, parent, owner)
{
handleEventsFor(this); // set self as command event handler
/**********************************************
* save comm window to restore focus by
* setFocus call when dialog is dismissed
*********************************************/
commWind = commWin;
/*******************************************
* set opponent and time control text values
*******************************************/
clock = new IEntryField(DID_MATCH_CLOCK, this);
clock->setText(cClock);
oddsClock = new IEntryField(DID_MATCH_ODDSCLOCK, this);
if (cOddsClock != "") {
oddsClock->setText(cOddsClock);
}
opponent = new IStaticText(DID_MATCH_OPPONENT, this);
opponent->setText(cName);
/*******************************************
* set rated, wild, colour buttons
*******************************************/
rated = new ICheckBox(DID_MATCH_RATED, this);
if (cIsRated)
rated->select();
wild = new ICheckBox(DID_MATCH_WILD, this);
wildType = new IEntryField(DID_MATCH_WILDTYPE, this);
if (cWildType) {
wild->select();
wildType->setText(IString(cWildType));
}
white = new IRadioButton(DID_MATCH_WHITE, this);
black = new IRadioButton(DID_MATCH_BLACK, this);
neutral = new IRadioButton(DID_MATCH_NEUTRAL, this);
if (cIsWhite)
white->select();
else if (cIsBlack)
black->select();
else
neutral->select();
/******************************************************************
* attach a handler to process check/radio box selections
******************************************************************/
selectHdr = new AMatchSelectHandler();
selectHdr->handleEventsFor(this);
/******************************************************************
* save initial parameters: if final parameters are the same,
* issue Accept instead of Match, because ics may reject a Match
* on the basis of Formulae.
******************************************************************/
initialClock = cClock;
initialOddsClock = cOddsClock;
initialRated = cIsRated;
initialWhite = cIsWhite;
initialBlack = cIsBlack;
initialWildType = cWildType;
show();
}
/**************************************************************************
* FUNCTION: command (class AMatchDialog)
*
* DESCRIPTION: event handler for dialog Accept/Ignore/Decline pushbuttons
*
**************************************************************************/
Boolean AMatchDialog:: command(ICommandEvent &cmdevt)
{
IFUNCTRACE_DEVELOP();
switch(cmdevt.commandId()) {
case DID_MATCH_ACCEPT:
{
IString s;
ITRACE_DEVELOP("match accepted");
/******************************************************************
* figure out if any parameters changed. if identical to the
* original challenge issue "accept", else issue "match" with
* all parameters specified explicitly. this distinction is
* because the opponent can issue a challenge that does not
* satisfy his own formula (e.g. he issues a rated challenge
* and his formula says unrated only) and if we echo back the match
* command ics will reject it.
******************************************************************/
if (clock->text() == initialClock &&
oddsClock->text() == initialOddsClock &&
wild->isSelected() == (initialWildType != 0) &&
wildType->text() == IString(initialWildType) &&
rated->isSelected() == initialRated &&
white->isSelected() == initialWhite &&
black->isSelected() == initialBlack) {
s = "\naccept "+ opponent->text().word(1) + "\n";
}
else {
//match <name> <time> <increment> <time2> <increment2> <r> <u> <wk> <color>
s = "\nmatch "+ opponent->text().word(1)+" "+ clock->text()+" ";
if (oddsClock->text() != IString(""))
s += oddsClock->text()+" ";
s += (rated->isSelected()) ? "r " : "u ";
if (wild->isSelected() && wildType->text() != IString(""))
s += "w"+wildType->text()+" ";
if (white->isSelected())
s += "white ";
if (black->isSelected())
s += "black ";
s += "\n";
}
aSession->write(s);
dismiss();
commWind->setFocus();
break;
}
case DID_MATCH_IGNORE:
ITRACE_DEVELOP("match ignored");
dismiss();
commWind->setFocus();
break;
case DID_MATCH_DECLINE:
ITRACE_DEVELOP("match declined");
aSession->write(IString("\ndecline ")+opponent->text().word(1)+"\n");
dismiss();
commWind->setFocus();
break;
}
return false; // pass to default processing
}
/**************************************************************************
* FUNCTION: command (class AMatchSelectHandler)
*
* DESCRIPTION: event handler for dialog radiobuttons and checkboxes
*
**************************************************************************/
Boolean AMatchSelectHandler:: selected(IControlEvent &evt)
{
AMatchDialog *dlg = (AMatchDialog *)evt.window();
IFUNCTRACE_DEVELOP();
switch(evt.controlId()) {
case DID_MATCH_RATED:
ITRACE_DEVELOP("match rated checked");
break;
case DID_MATCH_WILD:
ITRACE_DEVELOP("match wild checked");
break;
case DID_MATCH_WHITE:
ITRACE_DEVELOP("match white checked");
dlg->black->deselect();
dlg->neutral->deselect();
break;
case DID_MATCH_BLACK:
ITRACE_DEVELOP("match black checked");
dlg->white->deselect();
dlg->neutral->deselect();
break;
case DID_MATCH_NEUTRAL:
ITRACE_DEVELOP("match neutral checked");
dlg->white->deselect();
dlg->black->deselect();
break;
}
return false; // pass to default processing
}