1 /* This program is copyright 1993 by Andrew Plotkin.
2 The source code may be freely copied, distributed,
3 and modified, as long as this copyright notice is
4 retained.
5 */
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <X11/Xlib.h>
10 #include <X11/Xutil.h>
11
12 #include "handwave.h"
13 #include "spelllist.h"
14 #include "patchlevel.h"
15
16 #include "xspell.h"
17
18 int win_wid, win_hgt;
19
20 struct player *players;
21 int numplayers;
22 int turnstate;
23
24 game *gameval = NULL;
25
26 static int defaultnum = 0;
27 static char *defaultnamelist[10] = {"White", "Black", "Red", "Green", "Blue",
28 "Yellow", "Orange", "Purple", "Grey", "Charteuse"};
29 static char *namelist[MAXPLAYERS] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
30 static char *displist[MAXPLAYERS] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
31 static int genderlist[MAXPLAYERS] = {Gender_MALE, Gender_MALE, Gender_MALE,
32 Gender_MALE, Gender_MALE, Gender_MALE, Gender_MALE, Gender_MALE};
33
34 static struct query savequery = {
35 0,
36 Qu_SaveTranscript,
37 NULL,
38 0
39 };
40
41 static void PrintMsg(), PrintMsg2(), PrintMsg3();
42 extern void redraw();
43 extern void XQueries();
44
main(argc,argv)45 main(argc, argv)
46 int argc;
47 char *argv[];
48 {
49 struct interface procs;
50 struct maingame ignorerock;
51 static char inbuf[256];
52 int whowon;
53 int ix, val;
54 struct player *py;
55 int movelist[MAXPLAYERS*2];
56
57 procs.proc_PrintMsg = PrintMsg;
58 procs.proc_PrintMsg2 = PrintMsg2;
59 procs.proc_PrintMsg3 = PrintMsg3;
60 procs.proc_Queries = XQueries;
61
62 if (argc==1) {
63 printf("usage: spellcast RemoteDisplay [ RemoteDisplay2 ... ]\n");
64 exit(12);
65 }
66
67 numplayers = 1;
68 displist[0] = NULL;
69 for (ix=1; ix<argc; ix++) {
70 if (strlen(argv[ix])!=0) {
71 if (index(argv[ix], ':'))
72 displist[numplayers] = argv[ix];
73 else {
74 displist[numplayers] = (char *)malloc(strlen(argv[ix])+6);
75 strcpy(displist[numplayers], argv[ix]);
76 strcat(displist[numplayers], ":0.0");
77 }
78 }
79 else
80 displist[numplayers] = NULL;
81 /* allow an empty argument to signify NULL display */
82 numplayers++;
83 }
84
85 if (numplayers < 2) {
86 printf("You have listed only %d players!\n", numplayers);
87 exit(12);
88 }
89 if (numplayers > MAXPLAYERS) {
90 printf("There is a maximum of %d players!\n", MAXPLAYERS);
91 exit(12);
92 }
93
94 players = (struct player *)malloc(sizeof(struct player) * numplayers);
95
96 win_wid = 832;
97 if (numplayers > 3)
98 win_wid += (numplayers-3) * (2*GEST_SIZE + 20);
99 win_hgt = 750;
100 turnstate = State_Init;
101
102 for (ix=0; ix<numplayers; ix++) {
103 val = win_init(ix);
104 if (!val) {
105 fprintf(stderr, "spellcast: exiting.\n");
106 exit(-1);
107 }
108 }
109
110 gameval = BeginGame(numplayers, namelist, genderlist, &procs, &ignorerock);
111
112 do {
113 val = TurnType(gameval);
114 turnstate = State_Top;
115 for (ix=0; ix<numplayers; ix++) {
116 py = &(players[ix]);
117 py->turn_active = TurnPlayerActive(gameval, ix);
118 py->turn_done = !py->turn_active;
119 }
120 for (ix=0; ix<numplayers; ix++) {
121 py = &(players[ix]);
122 py->gesture_chosen[0] = Gesture_NOTHING;
123 py->gesture_chosen[1] = Gesture_NOTHING;
124 clear_answers(py);
125 if (py->turn_active)
126 switch (val) {
127 case Turn_HASTE:
128 add_answer(py, "Enter your gestures for your Hastened move.",
129 "", 1, 0, NULL, 0);
130 break;
131 case Turn_TIMESTOP:
132 add_answer(py, "Enter your gestures for your Time-Stopped move.",
133 "", 1, 0, NULL, 0);
134 break;
135 default:
136 add_answer(py,
137 "Enter your gestures for this move, at the bottom of your gesture list.",
138 "", 1, 0, NULL, 0);
139 break;
140 }
141 else
142 switch (val) {
143 case Turn_HASTE:
144 add_answer(py, "Other people are Hastened this turn.",
145 "", 1, 0, NULL, 0);
146 break;
147 case Turn_TIMESTOP:
148 add_answer(py, "You are frozen in time.", "", 1, 0, NULL, 0);
149 break;
150 default:
151 add_answer(py, "You are out of the game.", "", 1, 0, NULL, 0);
152 break;
153 }
154 redraw_column(py);
155 draw_button(py, 0, 1); /* redraw turn-end button */
156 redraw_queries_only(py, 0);
157 /*update_statlist(py);*/
158 }
159 mainloop();
160
161 for (ix=0; ix<numplayers; ix++) {
162 struct player *py = &(players[ix]);
163 movelist[ix*2+0] = py->gesture_chosen[0];
164 movelist[ix*2+1] = py->gesture_chosen[1];
165 }
166 whowon = RunTurn(gameval, movelist);
167 } while (whowon < 0);
168
169 if (whowon==MAXPLAYERS)
170 sprintf(inbuf, "\n+++ The game is a draw +++\n");
171 else
172 sprintf(inbuf, "\n+++ %s has won +++\n", NameOfBeing(gameval,
173 QuVal_Target_Wizard, whowon));
174 PrintMsg(inbuf, gameval, &ignorerock);
175 LogInTranscript(gameval, inbuf);
176 LogInTranscript(gameval, "\n");
177
178 turnstate = State_End;
179 for (ix=0; ix<numplayers; ix++) {
180 py = &(players[ix]);
181 py->turn_active = 1;
182 py->turn_done = 0;
183 }
184 for (ix=0; ix<numplayers; ix++) {
185 py = &(players[ix]);
186 clear_answers(py);
187 if (ix==0)
188 add_answer(py, "Do you want to save a transcript of this game?",
189 "No", 1, 0, &savequery, 0);
190 redraw_column(py);
191 draw_button(py, 0, 1); /* redraw turn-end button */
192 redraw_queries_only(py, 0);
193 /*update_statlist(py);*/
194 }
195 mainloop();
196
197 savequery.answer = players[0].answers[0].answer;
198 if (savequery.answer) {
199 char fname[512];
200 FILE *fl;
201
202 sprintf(fname, "%s/spellcast-%d", TRANSCRIPTDIR, getpid());
203 fl = fopen(fname, "w");
204 if (!fl) {
205 printf("spellcast: unable to open %s for writing\n", fname);
206 perror("spellcast: error");
207 }
208 else {
209 WriteTranscript((game *)gameval, fl);
210 fclose(fl);
211 printf("Saved transcript in %s.\n", fname);
212 }
213 }
214 FreeGame(gameval);
215
216 }
217
win_init(pnum)218 int win_init(pnum)
219 int pnum;
220 {
221 XSetWindowAttributes attr;
222 XGCValues gcvalues;
223 char winname[256];
224 char *fontname;
225 char *name, *tmp;
226 int ix, val;
227
228 struct player *py = &(players[pnum]);
229
230 py->dpy = XOpenDisplay(displist[pnum]);
231 if (!py->dpy) {
232 fprintf(stderr, "spellcast: could not open display for player %d.\n", pnum);
233 return 0;
234 }
235
236 py->scn = DefaultScreen(py->dpy);
237 py->win = XCreateSimpleWindow(py->dpy, DefaultRootWindow(py->dpy), 100, 100,
238 win_wid, win_hgt, 1, BlackPixel(py->dpy, py->scn),
239 WhitePixel(py->dpy, py->scn));
240 py->backpm = XCreatePixmap(py->dpy, py->win, win_wid, win_hgt,
241 DefaultDepth(py->dpy, py->scn));
242 py->backstore = 0;
243
244 { /* make some window managers happy */
245 XWMHints wmhints;
246 wmhints.flags = InputHint;
247 wmhints.input = True;
248 XSetWMHints(py->dpy, py->win, &wmhints);
249 }
250
251 attr.event_mask = EVENTMASK;
252 XChangeWindowAttributes(py->dpy, py->win, CWEventMask, &attr);
253
254 tmp = XGetDefault(py->dpy, "spellcast", "name");
255 if (tmp) {
256 name = (char *)malloc(strlen(tmp)+1);
257 strcpy(name, tmp);
258 tmp = index(name, ':');
259 if (!tmp)
260 genderlist[pnum] = Gender_MALE;
261 else {
262 switch (*(tmp+1)) {
263 case 'f':
264 case 'F':
265 genderlist[pnum] = Gender_FEMALE;
266 break;
267 case 'n':
268 case 'N':
269 genderlist[pnum] = Gender_NEUTER;
270 break;
271 case 'x':
272 case 'X':
273 genderlist[pnum] = Gender_NONE;
274 break;
275 case 'm':
276 case 'M':
277 default:
278 genderlist[pnum] = Gender_MALE;
279 break;
280 }
281 *tmp = '\0';
282 }
283 tmp = name+strlen(name)-1;
284 while (tmp>name && (*tmp==' ' || *tmp=='\t'))
285 tmp--;
286 *(tmp+1) = '\0';
287 namelist[pnum] = name;
288 }
289 else {
290 namelist[pnum] = defaultnamelist[defaultnum];
291 defaultnum++;
292 }
293
294 do {
295 val = 0;
296 if (strlen(namelist[pnum])<1)
297 val = 1;
298 if (!strcmp(namelist[pnum], "nobody"))
299 val = 1;
300 if (!strcmp(namelist[pnum], "Nobody"))
301 val = 1;
302 for (ix=0; ix<pnum; ix++)
303 if (!strcmp(namelist[pnum], namelist[ix]))
304 val = 1;
305
306 if (val) {
307 tmp = namelist[pnum];
308 namelist[pnum] = defaultnamelist[defaultnum];
309 defaultnum++;
310
311 fprintf(stderr,
312 "spellcast: the name '%s' for player %d is taken. Switching to '%s'...\n",
313 tmp, pnum, namelist[pnum]);
314 }
315 } while (val);
316
317 sprintf(winname, "Spellcast: %s", namelist[pnum]);
318 XStoreName(py->dpy, py->win, winname);
319
320 XMapWindow(py->dpy, py->win);
321
322 fontname = XGetDefault(py->dpy, "spellcast", "font");
323 if (!fontname)
324 fontname = BODYFONT;
325 py->font = XLoadQueryFont(py->dpy, fontname);
326
327 if (!py->font) {
328 fprintf(stderr,
329 "spellcast: could not find font %s for player %d. Switching to %s...\n",
330 fontname, pnum, BODYFONT_ALT);
331 py->font = XLoadQueryFont(py->dpy, BODYFONT_ALT);
332 if (!py->font) {
333 fprintf(stderr,
334 "spellcast: could not find font %s for player %d. Switching to %s...\n",
335 BODYFONT_ALT, pnum, BODYFONT_ALT2);
336 py->font = XLoadQueryFont(py->dpy, BODYFONT_ALT2);
337 if (!py->font) {
338 fprintf(stderr, "spellcast: could not find font %s for player %d.\n",
339 BODYFONT_ALT2, pnum);
340
341 return 0;
342 }
343
344 }
345 }
346
347 gcvalues.font = py->font->fid;
348 gcvalues.foreground = BlackPixel(py->dpy, py->scn);
349 gcvalues.background = WhitePixel(py->dpy, py->scn);
350 py->blackgc = XCreateGC(py->dpy, py->win, GCForeground|GCBackground|GCFont,
351 &gcvalues);
352 XSetGraphicsExposures(py->dpy, py->blackgc, 0);
353
354 gcvalues.foreground = WhitePixel(py->dpy, py->scn);
355 gcvalues.background = BlackPixel(py->dpy, py->scn);
356 py->whitegc = XCreateGC(py->dpy, py->win, GCForeground|GCBackground|GCFont,
357 &gcvalues);
358 XSetGraphicsExposures(py->dpy, py->whitegc, 0);
359
360 init_bitmaps(py);
361 init_xtext(pnum);
362 init_query(py);
363 init_stats(py);
364 init_talk(py);
365 py->button_lit = (-1);
366 redraw(py);
367
368 return 1;
369 }
370
371 #define POPUP_ELBOW (8)
372
adjust_rect(mrec)373 void adjust_rect(mrec)
374 struct rect *mrec;
375 {
376 if (mrec->x+mrec->w >= win_wid-POPUP_ELBOW)
377 mrec->x = win_wid-POPUP_ELBOW - mrec->w;
378 if (mrec->y+mrec->h >= win_hgt-POPUP_ELBOW)
379 mrec->y = win_hgt-POPUP_ELBOW - mrec->h;
380 if (mrec->x < POPUP_ELBOW)
381 mrec->x = POPUP_ELBOW;
382 if (mrec->y < POPUP_ELBOW)
383 mrec->y = POPUP_ELBOW;
384 }
385
backing_store(py,mrec)386 void backing_store(py, mrec)
387 struct player *py;
388 struct rect *mrec;
389 {
390 py->backrec = (*mrec);
391 if (py->backstore) {
392 printf("ERROR: backing store already on\n");
393 }
394 py->backstore = 1;
395 py->gotexpose = 0;
396 XCopyArea(py->dpy, py->win, py->backpm, py->blackgc, mrec->x, mrec->y,
397 mrec->w, mrec->h, 0, 0);
398 }
399
backing_restore(py)400 void backing_restore(py)
401 struct player *py;
402 {
403 if (!py->backstore) {
404 printf("ERROR: backing store already off\n");
405 }
406 py->backstore = 0;
407 if (py->gotexpose) {
408 XClearArea(py->dpy, py->win, py->backrec.x, py->backrec.y,
409 py->backrec.w, py->backrec.h, 0);
410 redraw(py);
411 }
412 else {
413 XCopyArea(py->dpy, py->backpm, py->win, py->blackgc, 0, 0,
414 py->backrec.w, py->backrec.h, py->backrec.x, py->backrec.y);
415 }
416 }
417
PrintMsg(msg,gameval,rock)418 static void PrintMsg(msg, gameval, rock)
419 char *msg;
420 game *gameval;
421 struct maingame *rock;
422 {
423 int ix;
424 if (msg) {
425 for (ix=0; ix<numplayers; ix++)
426 dump_text(ix, msg);
427 }
428 }
429
PrintMsg2(person1,msg1,msgelse,gameval,rock)430 static void PrintMsg2(person1, msg1, msgelse, gameval, rock)
431 int person1;
432 char *msg1, *msgelse;
433 game *gameval;
434 struct maingame *rock;
435 {
436 int ix;
437
438 for (ix=0; ix<numplayers; ix++) {
439 if (ix==person1) {
440 if (msg1)
441 dump_text(ix, msg1);
442 }
443 else {
444 if (msgelse)
445 dump_text(ix, msgelse);
446 }
447 }
448 }
449
PrintMsg3(person1,person2,msg1,msg2,msgelse,gameval,rock)450 static void PrintMsg3(person1, person2, msg1, msg2, msgelse, gameval, rock)
451 int person1, person2;
452 char *msg1, *msg2, *msgelse;
453 game *gameval;
454 struct maingame *rock;
455 {
456 int ix;
457
458 for (ix=0; ix<numplayers; ix++) {
459 if (ix==person1) {
460 if (msg1)
461 dump_text(ix, msg1);
462 }
463 else if (ix==person2) {
464 if (msg2)
465 dump_text(ix, msg2);
466 }
467 else {
468 if (msgelse)
469 dump_text(ix, msgelse);
470 }
471 }
472 }
473
474