1 /*
2  * src/client/match.c, part of Complete Goban (player program)
3  * Copyright (C) 1996 William Shubert
4  * See "configure.h.in" for more copyright information.
5  */
6 
7 #include <wms.h>
8 #include "../msg.h"
9 #include <but/but.h>
10 #include <but/plain.h>
11 #include <but/ctext.h>
12 #include <but/textin.h>
13 #include <but/checkbox.h>
14 #include <abut/msg.h>
15 #include "../goTime.h"
16 #ifdef  _CLIENT_MATCH_H_
17   Levelization Error.
18 #endif
19 #include "match.h"
20 
21 
22 /**********************************************************************
23  * Forward Declarations
24  **********************************************************************/
25 static ButOut  resize(ButWin *win);
26 static ButOut  destroy(ButWin *win);
27 static ButOut  newSize(But *but, const char *value);
28 static ButOut  newHcap(But *but, const char *value);
29 static ButOut  newKomi(But *but, const char *value);
30 static ButOut  newMainTime(But *but, const char *value);
31 static ButOut  newBYTime(But *but, const char *value);
32 static ButOut  okPressed(But *but);
33 static ButOut  cancelPressed(But *but);
34 static ButOut  newFree(But *but, bool newVal);
35 static ButOut  swapPressed(But *but);
36 static CliMatch  *playerLookup(CliMatch *chain, const char *player);
37 static ButOut  changeMain(But *but);
38 static ButOut  changeBy(But *but);
39 static ButOut  changeSize(But *but);
40 static ButOut  changeKomi(But *but);
41 static ButOut  changeHcap(But *but);
42 
43 
44 /**********************************************************************
45  * Functions
46  **********************************************************************/
cliMatch_matchCommand(CliData * data,const char * command,CliMatch ** next,int rankDiff)47 CliMatch  *cliMatch_matchCommand(CliData *data, const char *command,
48 				 CliMatch **next, int rankDiff)  {
49   char  oppName[21];
50   char  colorChar;
51   int  args, size, mainTime, byTime;
52   CliMatch  *match;
53 
54   args = sscanf(command, "Use <match %20s %c %d %d %d>",
55 		oppName, &colorChar, &size, &mainTime, &byTime);
56   assert(args == 5);
57   assert((colorChar == 'W') || (colorChar == 'B'));
58   match = playerLookup(*next, oppName);
59   if (match == NULL)  {
60     /* Start up a new match window. */
61     match = cliMatch_create(data, oppName, next, rankDiff);
62     if ((colorChar == 'B') != match->meFirst)
63       swapPressed(match->swap);
64   } else  {
65     /* Modify an old one. */
66     XRaiseWindow(butEnv_dpy(butWin_env(match->win)), butWin_xwin(match->win));
67     if ((colorChar == 'B') != match->meFirst)
68       swapPressed(match->swap);
69   }
70   str_print(&data->cmdBuild, "%d", match->size = size);
71   butTextin_set(match->sizeIn, str_chars(&data->cmdBuild), TRUE);
72   goTime_str(match->mainTime = mainTime * 60, &data->cmdBuild);
73   butTextin_set(match->mainIn, str_chars(&data->cmdBuild), TRUE);
74   goTime_str(match->byTime = byTime * 60, &data->cmdBuild);
75   butTextin_set(match->byIn, str_chars(&data->cmdBuild), TRUE);
76   match->state = cliMatch_recvd;
77   butText_set(match->title, msg_cliGameSetupRecvd);
78   return(match);
79 }
80 
81 
cliMatch_create(CliData * data,const char * oppName,CliMatch ** next,int rankDiff)82 CliMatch  *cliMatch_create(CliData *data, const char *oppName,
83 			   CliMatch **next, int rankDiff)  {
84   CliMatch  *m;
85   Cgoban  *cg;
86   int  i, h, w;
87   char  curText[20];
88   bool  err;
89   uint  flags;
90 
91   assert(MAGIC(data));
92   m = playerLookup(*next, oppName);
93   if (m != NULL)  {
94     XRaiseWindow(butEnv_dpy(butWin_env(m->win)), butWin_xwin(m->win));
95     return(m);
96   }
97   cg = data->cg;
98   m = wms_malloc(sizeof(CliMatch));
99   MAGIC_SET(m);
100   m->next = *next;
101   m->prev = next;
102   *next = m;
103   m->data = data;
104   m->state = cliMatch_nil;
105   if (rankDiff == 0)  {
106     m->meFirst = clp_getBool(cg->clp, "client.match.meFirst");
107     m->komi = 5.5;
108     m->hcap = 0;
109   } else if (rankDiff > 0)  {
110     m->meFirst = FALSE;
111     m->komi = 0.5;
112     m->hcap = 0;
113   } else /* rankDiff < 0 */  {
114     m->meFirst = TRUE;
115     m->komi = 0.5;
116     m->hcap = 0;
117   }
118   if (m->meFirst)  {
119     str_initChars(&m->wName, oppName);
120     str_initChars(&m->bName, str_chars(&data->userName));
121   } else  {
122     str_initChars(&m->bName, oppName);
123     str_initChars(&m->wName, str_chars(&data->userName));
124   }
125   h = cg->fontH * 18 + butEnv_stdBw(cg->env) * 19;
126   w = (h * 1.4142136) + 0.5;
127   m->win = butWin_create(m, cg->env, "Server Game Setup",
128 			 w, h, NULL, NULL, resize, destroy);
129   if (m->next == NULL)  {
130     /*
131      * We only want to set the window to the "standard" place if it is the
132      *   first one.  Otherwise all the windows would stack up on each other,
133      *   which is kind of annoying.
134      */
135     i = clp_iGetInt(cg->clp, "client.match.x", &err);
136     if (!err)
137       butWin_setX(m->win, i);
138     i = clp_iGetInt(cg->clp, "client.match.y", &err);
139     if (!err)
140       butWin_setY(m->win, i);
141   }
142   butWin_activate(m->win);
143   m->bg = butBoxFilled_create(m->win, 0, BUT_DRAWABLE);
144   butBoxFilled_setPixmaps(m->bg, cg->bgLitPixmap, cg->bgShadPixmap,
145 			  cg->bgPixmap);
146 
147   m->title = butText_create(m->win, 1, BUT_DRAWABLE, msg_cliGameSetup,
148 			     butText_center);
149   butText_setFont(m->title, 2);
150 
151   m->namesBox = butBox_create(m->win, 1, BUT_DRAWABLE);
152   butBox_setPixmaps(m->namesBox, cg->bgLitPixmap, cg->bgShadPixmap);
153 
154   m->wBox = butBoxFilled_create(m->win, 1, BUT_DRAWABLE);
155   butBoxFilled_setColors(m->wBox, BUT_LIT, BUT_SHAD, BUT_BG);
156   str_print(&data->cmdBuild, CGBUTS_WSTONECHAR " %s", str_chars(&m->wName));
157   m->wTitle = butText_create(m->win, 2, BUT_DRAWABLE,
158 			     str_chars(&data->cmdBuild), butText_left);
159 
160   m->bBox = butBoxFilled_create(m->win, 1, BUT_DRAWABLE);
161   butBoxFilled_setColors(m->bBox, BUT_LIT, BUT_SHAD, BUT_BG);
162   str_print(&data->cmdBuild, CGBUTS_BSTONECHAR " %s", str_chars(&m->bName));
163   m->bTitle = butText_create(m->win, 2, BUT_DRAWABLE,
164 			     str_chars(&data->cmdBuild), butText_left);
165 
166   m->swap = butAct_create(swapPressed, m, m->win, 1,
167 			  BUT_DRAWABLE|BUT_PRESSABLE,
168 			  msg_swapColors, BUT_ALEFT|BUT_ARIGHT);
169 
170   m->size = clp_getInt(cg->clp, "client.match.size");
171   m->mainTime = clp_getInt(cg->clp, "client.match.mainTime");
172   m->byTime = clp_getInt(cg->clp, "client.match.byTime");
173 
174   m->rulesBox = butBox_create(m->win, 1, BUT_DRAWABLE);
175   butBox_setPixmaps(m->rulesBox, cg->bgLitPixmap, cg->bgShadPixmap);
176   m->sizeStr = butText_create(m->win, 1, BUT_DRAWABLE,
177 			       msg_boardSize, butText_center);
178   sprintf(curText, "%d", m->size);
179   m->sizeIn = butTextin_create(newSize, m, m->win, 1,
180 				BUT_DRAWABLE|BUT_PRESSABLE, curText, 10);
181   flags = BUT_DRAWABLE;
182   if (m->size < 19)
183     flags |= BUT_PRESSABLE;
184   m->sizeUp = butAct_create(changeSize, m, m->win, 1, flags, CGBUTS_FWDCHAR,
185 			    BUT_RRIGHT|BUT_SLEFT);
186   flags = BUT_DRAWABLE;
187   if (m->size > 9)
188     flags |= BUT_PRESSABLE;
189   m->sizeDown = butAct_create(changeSize, m, m->win, 1, flags, CGBUTS_BACKCHAR,
190 			      BUT_RLEFT|BUT_SRIGHT);
191 
192   m->hcapStr = butText_create(m->win, 1, BUT_DRAWABLE,
193 			       msg_handicap, butText_center);
194   sprintf(curText, "%d", m->hcap);
195   m->hcapIn = butTextin_create(newHcap, m, m->win, 1,
196 			       BUT_DRAWABLE|BUT_PRESSABLE, curText, 10);
197   flags = BUT_DRAWABLE;
198   if (m->hcap < 9)
199     flags |= BUT_PRESSABLE;
200   m->hcapUp = butAct_create(changeHcap, m, m->win, 1, flags, CGBUTS_FWDCHAR,
201 			    BUT_RRIGHT|BUT_SLEFT);
202   flags = BUT_DRAWABLE;
203   if (m->hcap > 0)
204     flags |= BUT_PRESSABLE;
205   m->hcapDown = butAct_create(changeHcap, m, m->win, 1, flags, CGBUTS_BACKCHAR,
206 			      BUT_RLEFT|BUT_SRIGHT);
207 
208   m->komiStr = butText_create(m->win, 1, BUT_DRAWABLE,
209 			       msg_komi, butText_center);
210   sprintf(curText, "%g", m->komi);
211   m->komiIn = butTextin_create(newKomi, m, m->win, 1,
212 			       BUT_DRAWABLE|BUT_PRESSABLE, curText, 10);
213   m->komiUp = butAct_create(changeKomi, m, m->win, 1,
214 			    BUT_DRAWABLE|BUT_PRESSABLE, CGBUTS_FWDCHAR,
215 			    BUT_RRIGHT|BUT_SLEFT);
216   m->komiDown = butAct_create(changeKomi, m, m->win, 1,
217 			      BUT_DRAWABLE|BUT_PRESSABLE, CGBUTS_BACKCHAR,
218 			      BUT_RLEFT|BUT_SRIGHT);
219 
220   m->timeBox = butBox_create(m->win, 1, BUT_DRAWABLE);
221   butBox_setPixmaps(m->timeBox, cg->bgLitPixmap, cg->bgShadPixmap);
222 
223   m->mainStr = butText_create(m->win, 1, BUT_DRAWABLE,
224 			      msg_primaryTime, butText_center);
225   m->mainIn = butTextin_create(newMainTime, m, m->win, 1,
226 			       BUT_PRESSABLE|BUT_DRAWABLE,
227 			       clp_getStr(cg->clp, "client.match.mainTime"),
228 			       10);
229   m->mainUp1 = butAct_create(changeMain, m, m->win, 1,
230 			     BUT_DRAWABLE|BUT_PRESSABLE, CGBUTS_FWDCHAR,
231 			     BUT_SRIGHT|BUT_SLEFT);
232   flags = BUT_DRAWABLE;
233   m->mainTime = goTime_parseChars(butTextin_get(m->mainIn), FALSE, NULL);
234   if (m->mainTime > 0)
235     flags |= BUT_PRESSABLE;
236   m->mainDown1 = butAct_create(changeMain, m, m->win, 1, flags,
237 			       CGBUTS_BACKCHAR, BUT_SRIGHT|BUT_SLEFT);
238   m->mainUp5 = butAct_create(changeMain, m, m->win, 1,
239 			     BUT_DRAWABLE|BUT_PRESSABLE, CGBUTS_FFCHAR,
240 			     BUT_RRIGHT|BUT_SLEFT);
241   m->mainDown5 = butAct_create(changeMain, m, m->win, 1, flags,
242 			       CGBUTS_REWCHAR, BUT_RLEFT|BUT_SRIGHT);
243 
244   m->byStr = butText_create(m->win, 1, BUT_DRAWABLE,
245 			     msg_byoYomi, butText_center);
246   m->byIn = butTextin_create(newBYTime, m, m->win, 1,
247 			     BUT_PRESSABLE|BUT_DRAWABLE,
248 			     clp_getStr(cg->clp, "client.match.byTime"), 10);
249   m->byTime = goTime_parseChars(butTextin_get(m->byIn), FALSE, NULL);
250   m->byUp1 = butAct_create(changeBy, m, m->win, 1, BUT_DRAWABLE|BUT_PRESSABLE,
251 			   CGBUTS_FWDCHAR, BUT_SRIGHT|BUT_SLEFT);
252   flags = BUT_DRAWABLE;
253   if (m->byTime > 0)
254     flags |= BUT_PRESSABLE;
255   m->byDown1 = butAct_create(changeBy, m, m->win, 1, flags, CGBUTS_BACKCHAR,
256 			     BUT_SRIGHT|BUT_SLEFT);
257   m->byUp5 = butAct_create(changeBy, m, m->win, 1, BUT_DRAWABLE|BUT_PRESSABLE,
258 			   CGBUTS_FFCHAR, BUT_RRIGHT|BUT_SLEFT);
259   m->byDown5 = butAct_create(changeBy, m, m->win, 1, flags, CGBUTS_REWCHAR,
260 			     BUT_RLEFT|BUT_SRIGHT);
261 
262   m->freeTitle = butText_create(m->win, 1, BUT_DRAWABLE|BUT_PRESSABLE,
263 				msg_freeGame, butText_center);
264   m->freeGame = butCb_create(newFree, m, m->win, 1, BUT_DRAWABLE|BUT_PRESSABLE,
265 			     clp_getBool(cg->clp, "client.match.free"));
266 
267   m->help = butCt_create(cgoban_createHelpWindow,
268 			  &help_cliMatch, m->win, 1,
269 			  BUT_DRAWABLE|BUT_PRESSABLE, msg_help);
270   m->ok = butCt_create(okPressed, m, m->win, 1,
271 			BUT_DRAWABLE|BUT_PRESSABLE, msg_ok);
272   m->cancel = butCt_create(cancelPressed, m, m->win, 1,
273 			    BUT_DRAWABLE|BUT_PRESSABLE, msg_cancel);
274 
275   return(m);
276 }
277 
278 
cliMatch_destroy(CliMatch * match)279 void  cliMatch_destroy(CliMatch *match)  {
280   assert(MAGIC(match));
281   butWin_destroy(match->win);
282 }
283 
284 
cliMatch_destroyChain(CliMatch * match,const char * oppName,int * hcap,float * komi,bool * free)285 bool  cliMatch_destroyChain(CliMatch *match, const char *oppName,
286 			    int *hcap, float *komi, bool *free)  {
287   bool  result = FALSE;
288 
289   /*
290    * This code wouldn't work if things were done right in the but library
291    *   and the windows were destroyed as soon as I asked for it.  But since
292    *   the library is too broken for me to fix right now I'll have to do it
293    *   this way.  The second assert in the loop will fail when the but library
294    *   is rewritten to do things right.
295    */
296   while (match != NULL)  {
297     assert(MAGIC(match));
298     if (oppName != NULL)  {
299       if (!strcmp(oppName, str_chars(&match->wName)) ||
300 	  !strcmp(oppName, str_chars(&match->bName)))  {
301 	result = TRUE;
302 	*hcap = match->hcap;
303 	*komi = match->komi;
304 	*free = butCb_get(match->freeGame);
305 	match->state = cliMatch_nil;
306       }
307     }
308     cliMatch_destroy(match);
309     assert(MAGIC(match));
310     match = match->next;
311   }
312   return(result);
313 }
314 
315 
resize(ButWin * win)316 static ButOut  resize(ButWin *win)  {
317   CliMatch  *m = butWin_packet(win);
318   Cgoban  *cg;
319   int  w, butW, h, x, y;
320   int  bw, fh;
321   ButEnv  *env;
322 
323   assert(MAGIC(m));
324   cg = m->data->cg;
325   assert(MAGIC(cg));
326   env = cg->env;
327   bw = butEnv_stdBw(env);
328   fh = cg->fontH;
329   w = butWin_w(win);
330   h = butWin_h(win);
331   butW = w/2-5*bw;
332 
333   but_resize(m->bg, 0,0, w,h);
334   but_resize(m->title, 0,bw*2, w, fh*2);
335 
336   but_resize(m->namesBox, bw,bw*3+fh*2, w-bw*2,bw*4+fh*2);
337   but_resize(m->wBox, bw*3, bw*5+fh*2,
338 	     w/2 - (bw * 4 + fh * 4), fh * 2);
339   but_resize(m->wTitle, bw * 5, bw * 5 + fh * 2,
340 	     w/2 - (bw * 8 + fh * 4), fh * 2);
341   but_resize(m->bBox, w/2 + bw + fh*4, bw*5+fh*2,
342 	     w - (w/2+bw*4 + fh * 4), fh*2);
343   but_resize(m->bTitle, w/2 + bw * 3 + fh*4, bw*5+fh*2,
344 	     w - (w/2+bw*8 + fh * 4), fh*2);
345 
346   but_resize(m->swap, w/2 - fh * 4, bw*5+fh*2, fh * 8, fh * 2);
347 
348   y = bw*7+fh*4;
349   but_resize(m->rulesBox, bw,y, w/2-bw,fh*12+bw*9);
350 
351   but_resize(m->sizeStr, bw*3,y+bw*2+fh*0, butW,fh*2);
352   but_resize(m->sizeIn, bw*3+fh*2,y+bw*3+fh*2, butW-fh*4,fh*2);
353   but_resize(m->sizeDown, bw*3,y+bw*3+fh*2, fh*2,fh*2);
354   but_resize(m->sizeUp, bw*3+butW-fh*2,y+bw*3+fh*2, fh*2,fh*2);
355 
356   but_resize(m->hcapStr, bw*3,y+bw*4+fh*4, butW,fh*2);
357   but_resize(m->hcapIn, bw*3+fh*2,y+bw*5+fh*6, butW-fh*4,fh*2);
358   but_resize(m->hcapDown, bw*3,y+bw*5+fh*6, fh*2,fh*2);
359   but_resize(m->hcapUp, bw*3+butW-fh*2,y+bw*5+fh*6, fh*2,fh*2);
360 
361   but_resize(m->komiStr, bw*3,y+bw*6+fh*8, butW,fh*2);
362   but_resize(m->komiIn, bw*3+fh*2,y+bw*7+fh*10, butW-fh*4,fh*2);
363   but_resize(m->komiDown, bw*3,y+bw*7+fh*10, fh*2,fh*2);
364   but_resize(m->komiUp, bw*3+butW-fh*2,y+bw*7+fh*10, fh*2,fh*2);
365 
366   but_resize(m->timeBox, w/2,y, w-bw-w/2,fh*12+bw*9);
367   x = w/2 + bw*2;
368   butW = w-x-bw*3;
369 
370   but_resize(m->mainStr, x,y+bw*2+fh*0, butW,fh*2);
371   but_resize(m->mainIn, x+fh*4,y+bw*3+fh*2, butW-fh*8,fh*2);
372   but_resize(m->mainDown5, x,y+bw*3+fh*2, fh*2,fh*2);
373   but_resize(m->mainDown1, x+fh*2,y+bw*3+fh*2, fh*2,fh*2);
374   but_resize(m->mainUp1, x+butW-fh*4,y+bw*3+fh*2, fh*2,fh*2);
375   but_resize(m->mainUp5, x+butW-fh*2,y+bw*3+fh*2, fh*2,fh*2);
376 
377   but_resize(m->byStr, x,y+bw*4+fh*4, butW,fh*2);
378   but_resize(m->byIn, x+fh*4,y+bw*5+fh*6, butW-fh*8,fh*2);
379   but_resize(m->byDown5, x,y+bw*5+fh*6, fh*2,fh*2);
380   but_resize(m->byDown1, x+fh*2,y+bw*5+fh*6, fh*2,fh*2);
381   but_resize(m->byUp1, x+butW-fh*4,y+bw*5+fh*6, fh*2,fh*2);
382   but_resize(m->byUp5, x+butW-fh*2,y+bw*5+fh*6, fh*2,fh*2);
383 
384   but_resize(m->freeTitle, x,y+bw*6+fh*8, butW,fh*2);
385   but_resize(m->freeGame, x + butW/2 - fh,y+bw*7+fh*10, fh*2,fh*2);
386 
387   but_resize(m->help, bw*2,y+bw*10+fh*12, (w-bw*6+1)/3,fh*2);
388   but_resize(m->cancel, bw*3+(w-bw*6+1)/3,y+bw*10+fh*12,
389 	     w-2*(bw*3+(w-bw*6+1)/3),fh*2);
390   but_resize(m->ok, w-(bw*2+(w-bw*6+1)/3),y+bw*10+fh*12,
391 	     (w-bw*6+1)/3,fh*2);
392 
393   return(0);
394 }
395 
396 
destroy(ButWin * win)397 static ButOut  destroy(ButWin *win)  {
398   CliMatch  *m;
399   Clp  *clp;
400   Str  *opp;
401 
402   m = butWin_packet(win);
403   assert(MAGIC(m));
404   if (m->state != cliMatch_nil)  {
405     if (m->meFirst)
406       opp = &m->wName;
407     else
408       opp = &m->bName;
409     str_print(&m->data->cmdBuild, "decline %s\n", str_chars(opp));
410     cliConn_send(&m->data->conn, str_chars(&m->data->cmdBuild));
411   }
412   clp = m->data->cg->clp;
413   clp_setInt(clp, "client.match.x", butWin_x(win));
414   clp_setInt(clp, "client.match.y", butWin_y(win));
415   clp_setBool(clp, "client.match.meFirst", m->meFirst);
416   str_deinit(&m->wName);
417   str_deinit(&m->bName);
418   *(m->prev) = m->next;
419   MAGIC_UNSET(m);
420   wms_free(m);
421   return(0);
422 }
423 
424 
newSize(But * but,const char * value)425 static ButOut  newSize(But *but, const char *value)  {
426   CliMatch  *m = but_packet(but);
427   int  newSize;
428   char  curValue[3];
429 
430   assert(MAGIC(m));
431   newSize = atoi(value);
432   if ((newSize > 19) ||
433       !clp_setStr(m->data->cg->clp, "client.match.size", value))  {
434     str_print(&m->data->cmdBuild, msg_badSize, value, 19);
435     cgoban_createMsgWindow(m->data->cg, "Cgoban Error",
436 			   str_chars(&m->data->cmdBuild));
437     sprintf(curValue, "%d", m->size);
438     butTextin_set(but, curValue, FALSE);
439     return(BUTOUT_ERR);
440   }
441   m->size = newSize;
442   if (m->size > 9)  {
443     but_setFlags(m->sizeDown, BUT_PRESSABLE);
444   } else  {
445     but_setFlags(m->sizeDown, BUT_NOPRESS);
446   }
447   if (m->size < 19)
448     but_setFlags(m->sizeUp, BUT_PRESSABLE);
449   else
450     but_setFlags(m->sizeUp, BUT_NOPRESS);
451   return(0);
452 }
453 
454 
newHcap(But * but,const char * value)455 static ButOut  newHcap(But *but, const char *value)  {
456   CliMatch  *m = but_packet(but);
457   int  newHcap;
458   char  curValue[2];
459   bool  err;
460 
461   assert(MAGIC(m));
462   newHcap = wms_atoi(value, &err);
463   if ((newHcap > 9) || (newHcap == 1) || (newHcap < 0) || err)  {
464     str_print(&m->data->cmdBuild, msg_badHcap, value, 9);
465     cgoban_createMsgWindow(m->data->cg, "Cgoban Error",
466 			   str_chars(&m->data->cmdBuild));
467     sprintf(curValue, "%d", m->hcap);
468     butTextin_set(but, curValue, FALSE);
469     return(BUTOUT_ERR);
470   }
471   m->hcap = newHcap;
472   if (m->hcap > 0)  {
473     but_setFlags(m->hcapDown, BUT_PRESSABLE);
474   } else  {
475     but_setFlags(m->hcapDown, BUT_NOPRESS);
476   }
477   if (m->hcap < 9)
478     but_setFlags(m->hcapUp, BUT_PRESSABLE);
479   else
480     but_setFlags(m->hcapUp, BUT_NOPRESS);
481   return(0);
482 }
483 
484 
newKomi(But * but,const char * value)485 static ButOut  newKomi(But *but, const char *value)  {
486   CliMatch  *m = but_packet(but);
487   float  newKomi;
488   char  curValue[7];
489   bool  err;
490 
491   assert(MAGIC(m));
492   newKomi = wms_atof(value, &err);
493   if ((newKomi > 999.5) || (newKomi < -999.5) || err ||
494       ((int)(newKomi * 2.0) != newKomi * 2.0))  {
495     str_print(&m->data->cmdBuild, msg_badKomi, value);
496     cgoban_createMsgWindow(m->data->cg, "Cgoban Error",
497 			   str_chars(&m->data->cmdBuild));
498     sprintf(curValue, "%g", m->komi);
499     butTextin_set(but, curValue, FALSE);
500     return(BUTOUT_ERR);
501   }
502   m->komi = newKomi;
503   if (m->komi > -99.5)  {
504     but_setFlags(m->hcapDown, BUT_PRESSABLE);
505   } else  {
506     but_setFlags(m->hcapDown, BUT_NOPRESS);
507   }
508   if (m->hcap < 99.5)
509     but_setFlags(m->hcapUp, BUT_PRESSABLE);
510   else
511     but_setFlags(m->hcapUp, BUT_NOPRESS);
512   return(0);
513 }
514 
515 
newMainTime(But * but,const char * value)516 static ButOut  newMainTime(But *but, const char *value)  {
517   CliMatch  *m = but_packet(but);
518   Str  errMsg;
519 
520   assert(MAGIC(m));
521   if (!clp_setStr(m->data->cg->clp, "client.match.mainTime", value))  {
522     str_init(&errMsg);
523     str_print(&errMsg, msg_badTime, value);
524     cgoban_createMsgWindow(m->data->cg, "Cgoban Error", str_chars(&errMsg));
525     goTime_str(m->mainTime, &errMsg);
526     butTextin_set(but, str_chars(&errMsg), FALSE);
527     str_deinit(&errMsg);
528     return(BUTOUT_ERR);
529   }
530   m->mainTime = goTime_parseChars(value, FALSE, NULL);
531   if (but_getFlags(but) & BUT_KEYED)
532     but_setFlags(m->byIn, BUT_KEYED);
533   if (m->mainTime > 0)  {
534     but_setFlags(m->mainDown1, BUT_PRESSABLE);
535     but_setFlags(m->mainDown5, BUT_PRESSABLE);
536   } else  {
537     but_setFlags(m->mainDown1, BUT_NOPRESS);
538     but_setFlags(m->mainDown5, BUT_NOPRESS);
539   }
540   return(0);
541 }
542 
543 
newBYTime(But * but,const char * value)544 static ButOut  newBYTime(But *but, const char *value)  {
545   CliMatch  *m = but_packet(but);
546   Str  errMsg;
547 
548   assert(MAGIC(m));
549   if (!clp_setStr(m->data->cg->clp, "client.match.byTime", value))  {
550     str_init(&errMsg);
551     str_print(&errMsg, msg_badTime, value);
552     cgoban_createMsgWindow(m->data->cg, "Cgoban Error", str_chars(&errMsg));
553     goTime_str(m->byTime, &errMsg);
554     butTextin_set(but, str_chars(&errMsg), FALSE);
555     str_deinit(&errMsg);
556     return(BUTOUT_ERR);
557   }
558   m->byTime = goTime_parseChars(value, FALSE, NULL);
559   but_setFlags(but, BUT_NOKEY);
560   if (m->byTime > 0)  {
561     but_setFlags(m->byDown1, BUT_PRESSABLE);
562     but_setFlags(m->byDown5, BUT_PRESSABLE);
563   } else  {
564     but_setFlags(m->byDown1, BUT_NOPRESS);
565     but_setFlags(m->byDown5, BUT_NOPRESS);
566   }
567   return(0);
568 }
569 
570 
okPressed(But * but)571 static ButOut  okPressed(But *but)  {
572   CliMatch  *m = but_packet(but);
573   const char  *oppName, *myName;
574   ButOut  result;
575 
576   assert(MAGIC(m));
577   if (m->meFirst)  {
578     oppName = str_chars(&m->wName);
579     myName = str_chars(&m->bName);
580   } else  {
581     myName = str_chars(&m->wName);
582     oppName = str_chars(&m->bName);
583   }
584   result = newSize(m->sizeIn, butTextin_get(m->sizeIn)) |
585     newMainTime(m->mainIn, butTextin_get(m->mainIn)) |
586       newBYTime(m->byIn, butTextin_get(m->byIn));
587   if (!(result & BUTOUT_ERR))  {
588     str_print(&m->data->cmdBuild,
589 	      "match %s %c %d %d %d\n"
590 	      "tell %s CLIENT: <cgoban " VERSION "> match %s wants "
591 	      "handicap %d, komi %g",
592 	      oppName,
593 	      (int)("wb"[m->meFirst]),
594 	      m->size, (m->mainTime + 59) / 60, (m->byTime + 59) / 60,
595 	      oppName, myName, m->hcap, m->komi);
596     if (butCb_get(m->freeGame))
597       str_catChars(&m->data->cmdBuild, ", free\n");
598     else
599       str_catChar(&m->data->cmdBuild, '\n');
600     cliConn_send(&m->data->conn, str_chars(&m->data->cmdBuild));
601     m->state = cliMatch_sent;
602     butText_set(m->title, msg_cliGameSetupSent);
603   }
604   return(result);
605 }
606 
607 
cancelPressed(But * but)608 static ButOut  cancelPressed(But *but)  {
609   butWin_destroy(but_win(but));
610   return(0);
611 }
612 
613 
newFree(But * but,bool newVal)614 static ButOut  newFree(But *but, bool newVal)  {
615   CliMatch  *m;
616 
617   m = but_packet(but);
618   assert(MAGIC(m));
619   clp_setBool(m->data->cg->clp, "client.match.free", newVal);
620   return(0);
621 }
622 
623 
swapPressed(But * but)624 static ButOut  swapPressed(But *but)  {
625   CliMatch  *m;
626   Str  temp, *cmdBuild;
627 
628   m = but_packet(but);
629   assert(MAGIC(m));
630   temp = m->wName;
631   m->wName = m->bName;
632   m->bName = temp;
633   m->meFirst = !m->meFirst;
634   cmdBuild = &m->data->cmdBuild;
635   str_print(cmdBuild, CGBUTS_WSTONECHAR " %s", str_chars(&m->wName));
636   butText_set(m->wTitle, str_chars(cmdBuild));
637   str_print(cmdBuild, CGBUTS_BSTONECHAR " %s", str_chars(&m->bName));
638   butText_set(m->bTitle, str_chars(cmdBuild));
639   return(0);
640 }
641 
642 
cliMatch_declineCommand(CliMatch * match,const char * buf)643 void  cliMatch_declineCommand(CliMatch *match, const char *buf)  {
644   char  name[30];
645 
646   sscanf(buf, "%s", name);
647   match = playerLookup(match, name);
648   if (match != NULL)  {
649     match->state = cliMatch_nil;
650     butText_set(match->title, msg_cliGameSetupRej);
651   }
652 }
653 
654 
playerLookup(CliMatch * chain,const char * player)655 static CliMatch  *playerLookup(CliMatch *chain, const char *player)  {
656   while (chain != NULL)  {
657     if (!strcmp(player, str_chars(&chain->wName)) ||
658 	!strcmp(player, str_chars(&chain->bName)))
659       return(chain);
660     chain = chain->next;
661   }
662   return(NULL);
663 }
664 
665 
changeMain(But * but)666 static ButOut  changeMain(But *but)  {
667   CliMatch  *m = but_packet(but);
668 
669   assert(MAGIC(m));
670   if (newMainTime(m->mainIn, butTextin_get(m->mainIn)) & BUTOUT_ERR)
671     return(BUTOUT_ERR);
672   if (but == m->mainUp1)  {
673     m->mainTime += 60;
674   } else if (but == m->mainUp5)  {
675     m->mainTime += 60 * 5;
676   } else if (but == m->mainDown1)  {
677     m->mainTime -= 60;
678     if (m->mainTime < 0)
679       m->mainTime = 0;
680   } else  {
681     assert(but == m->mainDown5);
682     m->mainTime -= 60 * 5;
683     if (m->mainTime < 0)
684       m->mainTime = 0;
685   }
686   goTime_str(m->mainTime, &m->data->cmdBuild);
687   butTextin_set(m->mainIn, str_chars(&m->data->cmdBuild), TRUE);
688   return(0);
689 }
690 
691 
changeBy(But * but)692 static ButOut  changeBy(But *but)  {
693   CliMatch  *m = but_packet(but);
694 
695   assert(MAGIC(m));
696   if (newBYTime(m->byIn, butTextin_get(m->byIn)) & BUTOUT_ERR)
697     return(BUTOUT_ERR);
698   if (but == m->byUp1)  {
699     m->byTime += 60;
700   } else if (but == m->byUp5)  {
701     m->byTime += 60 * 5;
702   } else if (but == m->byDown1)  {
703     m->byTime -= 60;
704     if (m->byTime < 0)
705       m->byTime = 0;
706   } else  {
707     assert(but == m->byDown5);
708     m->byTime -= 60 * 5;
709     if (m->byTime < 0)
710       m->byTime = 0;
711   }
712   goTime_str(m->byTime, &m->data->cmdBuild);
713   butTextin_set(m->byIn, str_chars(&m->data->cmdBuild), TRUE);
714   return(0);
715 }
716 
717 
changeSize(But * but)718 static ButOut  changeSize(But *but)  {
719   CliMatch  *m = but_packet(but);
720   char  sizeStr[3];
721 
722   assert(MAGIC(m));
723   if (newSize(m->sizeIn, butTextin_get(m->sizeIn)) & BUTOUT_ERR)
724     return(BUTOUT_ERR);
725   if (but == m->sizeUp)  {
726     if (m->size < 13)
727       m->size = 13;
728     else
729       m->size = 19;
730   } else  {
731     assert(but == m->sizeDown);
732     if (m->size > 13)
733       m->size = 13;
734     else
735       m->size = 9;
736   }
737   sprintf(sizeStr, "%d", m->size);
738   butTextin_set(m->sizeIn, sizeStr, TRUE);
739   return(0);
740 }
741 
742 
changeKomi(But * but)743 static ButOut  changeKomi(But *but)  {
744   CliMatch  *m = but_packet(but);
745   char  komiStr[10];
746 
747   assert(MAGIC(m));
748   if (newKomi(m->komiIn, butTextin_get(m->komiIn)) & BUTOUT_ERR)
749     return(BUTOUT_ERR);
750   if (but == m->komiUp)  {
751     m->komi += 1.0;
752     if (m->komi > 99.5)
753       m->komi = 99.5;
754   } else  {
755     assert(but == m->komiDown);
756     m->komi -= 1.0;
757     if (m->komi < -99.5)
758       m->komi = -99.5;
759   }
760   sprintf(komiStr, "%g", m->komi);
761   butTextin_set(m->komiIn, komiStr, TRUE);
762   return(0);
763 }
764 
765 
changeHcap(But * but)766 static ButOut  changeHcap(But *but)  {
767   CliMatch  *m = but_packet(but);
768   char  hcapStr[3];
769 
770   assert(MAGIC(m));
771   if (newHcap(m->hcapIn, butTextin_get(m->hcapIn)) & BUTOUT_ERR)
772     return(BUTOUT_ERR);
773   if (but == m->hcapUp)  {
774     ++m->hcap;
775     if (m->hcap == 1)
776       m->hcap = 2;
777     if (m->hcap > 9)
778       m->hcap = 9;
779   } else  {
780     assert(but == m->hcapDown);
781     --m->hcap;
782     if (m->hcap == 1)
783       m->hcap = 0;
784     if (m->hcap < 0)
785       m->hcap = 0;
786   }
787   sprintf(hcapStr, "%d", m->hcap);
788   butTextin_set(m->hcapIn, hcapStr, TRUE);
789   return(0);
790 }
791 
792 
cliMatch_extraInfo(CliMatch * match,const char * oppName,int hcap,float komi,bool free)793 void  cliMatch_extraInfo(CliMatch *match, const char *oppName, int hcap,
794 			 float komi, bool free)  {
795   char  temp[20];
796 
797   match = playerLookup(match, oppName);
798   if (match != NULL)  {
799     sprintf(temp, "%d", hcap);
800     butTextin_set(match->hcapIn, temp, TRUE);
801     sprintf(temp, "%g", komi);
802     butTextin_set(match->komiIn, temp, TRUE);
803     match->komi = komi;
804     butCb_set(match->freeGame, free, TRUE);
805   }
806 }
807