1 #include <stdio.h>
2 #include <string.h>
3 #include <X11/Xlib.h>
4 #include <X11/Xutil.h>
5 #include "handwave.h"
6 #include "spelllist.h"
7 #include "xspell.h"
8 
9 #define QUERY_X  (32)
10 #define QUERY_Y  (620)
11 #define QUERY_W  (736)
12 #define QUERY_H  (100)
13 #define QUERY_AW  (450)
14 
15 #define QUERY_LEADING (8)
16 #define QMENU_LEADING (4)
17 #define QMENU_BORDER (4)
18 
19 #define GEST_SPACE (50)
20 
21 typedef struct _tempstring {
22     struct _tempstring *next;
23     char str[1];
24 } tempstring;
25 
26 static char *TLElementalType_Names[] = {"Fire", "Ice"};
27 static char *TLHand_Names[] = {"Left", "Right"};
28 static char *TLNoYes_Names[] = {"No", "Yes"};
29 static int TLZeroOne_Num[] = {0, 1};
30 static struct target_list TLBeing = {0, NULL, NULL, 0};
31 static struct target_list TLBeingNone = {0, NULL, NULL, 0};
32 static struct target_list TLWizard = {0, NULL, NULL, 0};
33 static struct target_list TLWizardNone = {0, NULL, NULL, 0};
34 static struct target_list TLRaiseDead = {0, NULL, NULL, 0};
35 static struct target_list TLElementalType = {2, TLElementalType_Names, TLZeroOne_Num, 0};
36 static struct target_list TLPickHand = {2, TLHand_Names, TLZeroOne_Num, 0};
37 static struct target_list TLNoYes = {2, TLNoYes_Names, TLZeroOne_Num, 0};
38 
39 static tempstring *tempstringlist = NULL;
40 
41 void redraw_queries_only();
42 
init_query(py)43 void init_query(py)
44 struct player *py;
45 {
46     py->answers_size = 8;
47     py->answers = (struct answer *)malloc(sizeof(struct answer) * py->answers_size);
48     py->siquery.nlines = 0;
49     py->query_hgt = py->lineheight + QUERY_LEADING;
50     py->siquery.visible = QUERY_H / py->query_hgt;
51 
52     py->TLLeftHand.size = 0;
53     py->TLLeftHand.num = 0;
54     py->TLRightHand.size = 0;
55     py->TLRightHand.num = 0;
56 
57     py->siquery.py = py;
58     py->siquery.top = 0;
59     py->siquery.lineheight = py->query_hgt;
60     py->siquery.x = QUERY_X;
61     py->siquery.y = QUERY_Y;
62     py->siquery.h = QUERY_H;
63     py->siquery.redraw = redraw_queries_only;
64 }
65 
flush_tempstrings()66 void flush_tempstrings()
67 {
68     tempstring *pt;
69 
70     while (tempstringlist) {
71 	pt = tempstringlist->next;
72 	free(tempstringlist);
73 	tempstringlist = pt;
74     }
75 }
76 
tempstring_malloc(len)77 char *tempstring_malloc(len)
78 int len;
79 {
80     tempstring *pt;
81 
82     pt = (tempstring *)malloc(sizeof(tempstring) + len + 1);
83     pt->next = tempstringlist;
84     tempstringlist = pt;
85     return (pt->str);
86 }
87 
clear_answers(py)88 void clear_answers(py)
89 struct player *py;
90 {
91     py->siquery.nlines = 0;
92     py->siquery.top = 0;
93 }
94 
add_answer(py,qu_str,ans_str,done_init,answer_init,qrock,introck)95 void add_answer(py, qu_str, ans_str, done_init, answer_init, qrock, introck)
96 struct player *py;
97 char *qu_str;
98 char *ans_str;
99 int done_init, answer_init;
100 struct query *qrock;
101 long introck;
102 {
103     int num;
104 
105     if (py->siquery.nlines >= py->answers_size) {
106 	py->answers_size *= 2;
107 	py->answers = (struct answer *)realloc(py->answers,
108 			sizeof(struct answer) * py->answers_size);
109     }
110     num = py->siquery.nlines;
111     py->siquery.nlines++;
112     py->answers[num].done = done_init;
113     py->answers[num].answer = answer_init;
114     py->answers[num].query = qrock;
115     py->answers[num].rock = introck;
116     strcpy(py->answers[num].qu_str, qu_str);
117     strcpy(py->answers[num].ans_str, ans_str);
118 }
119 
DrawStringField(py,str,xpos,ypos,width)120 int DrawStringField(py, str, xpos, ypos, width)
121 struct player *py;
122 char *str;
123 int xpos, ypos;
124 int width;
125 {
126     static XCharStruct overall;
127     int direction, ascent, descent;
128     int len = strlen(str);
129 
130     XTextExtents(py->font, str, len, &direction, &ascent, &descent, &overall);
131     XDrawImageString(py->dpy, py->win, py->blackgc, xpos, ypos, str, len);
132     if (overall.width<width) {
133 	XClearArea(py->dpy, py->win, xpos+overall.width, ypos-py->ascent,
134 			width-overall.width, py->totalheight, 0);
135     }
136 
137     return overall.width;
138 }
139 
redraw_queries_only(py,baronly)140 void redraw_queries_only(py, baronly)
141 struct player *py;
142 int baronly;
143 {
144     int ix, qline;
145     int ypos;
146 
147     if (!baronly) {
148 	for (ix=0; ix<py->siquery.visible; ix++) {
149 	    qline = py->siquery.top + ix;
150 	    if (qline<0)
151 		continue;
152 	    ypos = QUERY_Y+ix*py->query_hgt+py->lineheight;
153 	    if (qline >= py->siquery.nlines) {
154 		DrawStringField(py, "", QUERY_X+16, ypos, QUERY_W-16);
155 	    }
156 	    else {
157 		DrawStringField(py, py->answers[qline].qu_str, QUERY_X+16,
158 				ypos, QUERY_AW-16);
159 		DrawStringField(py, py->answers[qline].ans_str, QUERY_X+QUERY_AW,
160 				ypos, QUERY_W-QUERY_AW);
161 	    }
162 	}
163     }
164 
165     redraw_scrollbar(&(py->siquery));
166 }
167 
redraw_queries(py)168 void redraw_queries(py)
169 struct player *py;
170 {
171     int ix;
172 
173     XDrawRectangle(py->dpy, py->win, py->blackgc, QUERY_X-3, QUERY_Y-2,
174 		QUERY_W+4, QUERY_H+3);
175     XDrawRectangle(py->dpy, py->win, py->blackgc, QUERY_X-SCROLL_W, QUERY_Y-2,
176 		SCROLL_W-3, QUERY_H+3);
177 
178     for (ix=0; ix<py->siquery.visible; ix++) {
179 	if (ix!=0)
180 	    XDrawLine(py->dpy, py->win, py->blackgc, QUERY_X, QUERY_Y+ix*py->query_hgt,
181 			QUERY_X+QUERY_W, QUERY_Y+ix*py->query_hgt);
182     }
183     redraw_queries_only(py, 0);
184 }
185 
add_to_targetlist(tl,name,targnum)186 static void add_to_targetlist(tl, name, targnum)
187 struct target_list *tl;
188 char *name;
189 int targnum;
190 {
191     int size;
192 
193     if (tl->size==0) {
194 	tl->size = 8;
195 	tl->tnums = (int *)malloc(tl->size*sizeof(int));
196 	tl->tnames = (char **)malloc(tl->size*sizeof(char *));
197     }
198 
199     size = tl->num;
200     tl->num++;
201 
202     if (tl->size <= size) {
203 	while (tl->size <= size)
204 	    tl->size *= 2;
205 	tl->tnums = (int *)realloc(tl->tnums, tl->size*sizeof(int));
206 	tl->tnames = (char **)realloc(tl->tnames, tl->size*sizeof(char *));
207     }
208 
209     tl->tnums[size] = targnum;
210     tl->tnames[size] = name;
211 }
212 
invent_target_lists()213 static void invent_target_lists()
214 {
215     int jx, numtargs;
216     char *nm, *realnm;
217     int tl;
218     long stuff;
219 
220     TLBeing.num = 0;
221     TLBeingNone.num = 0;
222     TLWizard.num = 0;
223     TLWizardNone.num = 0;
224     TLRaiseDead.num = 0;
225 
226     add_to_targetlist(&TLBeingNone, "nobody", 0);
227     add_to_targetlist(&TLWizardNone, "nobody", 0);
228 
229     numtargs = NumberOfTargets(gameval, QuVal_Target_Wizard);
230     for (jx=0; jx<numtargs; jx++) {
231 	tl = jx | QuVal_Target_Wizard;
232 	realnm = NameOfTarget(gameval, QuVal_Target_Wizard, jx);
233 	stuff = StuffAboutTarget(gameval, QuVal_Target_Wizard, jx);
234 	if (stuff & Stuff_INVISIBLE) {
235 	    nm = tempstring_malloc(sizeof(char) * (strlen(realnm) + 15));
236 	    strcpy(nm, realnm);
237 	    strcat(nm, " [invisible]");
238 	}
239 	else
240 	    nm = realnm;
241 	add_to_targetlist(&TLBeing, nm, tl);
242 	add_to_targetlist(&TLBeingNone, nm, tl);
243 	add_to_targetlist(&TLWizard, nm, tl);
244 	add_to_targetlist(&TLWizardNone, nm, tl);
245 	add_to_targetlist(&TLRaiseDead, nm, tl);
246     }
247 
248     numtargs = NumberOfTargets(gameval, QuVal_Target_Creature);
249     for (jx=0; jx<numtargs; jx++) {
250 	tl = jx | QuVal_Target_Creature;
251 	realnm = NameOfTarget(gameval, QuVal_Target_Creature, jx);
252 	stuff = StuffAboutTarget(gameval, QuVal_Target_Creature, jx);
253 	if (stuff & Stuff_INVISIBLE) {
254 	    nm = tempstring_malloc(sizeof(char) * (strlen(realnm) + 15));
255 	    strcpy(nm, realnm);
256 	    strcat(nm, " [invisible]");
257 	}
258 	else
259 	    nm = realnm;
260 	add_to_targetlist(&TLBeing, nm, tl);
261 	add_to_targetlist(&TLBeingNone, nm, tl);
262 	add_to_targetlist(&TLRaiseDead, nm, tl);
263     }
264 
265     numtargs = NumberOfTargets(gameval, QuVal_Target_Corpse);
266     for (jx=0; jx<numtargs; jx++) {
267 	tl = jx | QuVal_Target_Corpse;
268 	realnm = NameOfTarget(gameval, QuVal_Target_Corpse, jx);
269 	nm = tempstring_malloc(sizeof(char) * (strlen(realnm) + 10));
270 	strcpy(nm, realnm);
271 	strcat(nm, " [dead]");
272 	add_to_targetlist(&TLRaiseDead, nm, tl);
273     }
274 }
275 
XQueries(numqueries,qlist,gameval,rock)276 void XQueries(numqueries, qlist, gameval, rock)
277 int numqueries;
278 struct query qlist[];
279 game *gameval;
280 struct maingame *rock;
281 {
282     int ix, jx, kx;
283     char *handage;
284     int spellnum, attnum;
285     struct player *py;
286     int *hlist;
287     int gotany = 0;
288     int pnum;
289     int answer_init;
290     struct target_list *tl;
291     static qu_buf[MAXQUESTIONLENGTH], ans_buf[MAXANSWERLENGTH];
292 
293     flush_tempstrings();
294 
295     turnstate = State_Queries;
296     for (ix=0; ix<numplayers; ix++) {
297 	py = &(players[ix]);
298 	py->turn_active = 0;
299 	clear_answers(py);
300     }
301 
302     for (ix=0; ix<numqueries; ix++) {
303 	if (qlist[ix].qtype==Qu_NoQuery)
304 	    continue;
305 	py = &(players[qlist[ix].player]);
306 	py->turn_active = 1;
307 	pnum = py-players;
308 	gotany = 1;
309 	switch (qlist[ix].qtype) {
310 	    case Qu_LeftHand:
311 	    case Qu_RightHand:
312 		if (qlist[ix].qtype==Qu_LeftHand) {
313 		    strcpy(qu_buf, "What spell do you want to cast with your left hand?");
314 		    tl = &(py->TLLeftHand);
315 		}
316 		else {
317 		    strcpy(qu_buf, "What spell do you want to cast with your right hand?");
318 		    tl = &(py->TLRightHand);
319 		}
320 		hlist = (int *)qlist[ix].rock;
321 		tl->num = 0;
322 		for (jx=0; jx<hlist[0]; jx++) {
323 		    spellnum = hlist[jx+1];
324 		    if (spellnum & QuVal_Hand_Both) {
325 			handage = tempstring_malloc(sizeof(char) *
326 					(strlen(spelllist[spellnum &
327 					(~QuVal_Hand_Both)].name) + 16));
328 			sprintf(handage, "%s [both hands]",
329 					spelllist[spellnum &
330 					(~QuVal_Hand_Both)].name);
331 		    }
332 		    else
333 			handage = spelllist[spellnum & (~QuVal_Hand_Both)].name;
334 		    add_to_targetlist(tl, handage, jx);
335 		}
336 		strcpy(ans_buf, "");
337 		add_answer(py, qu_buf, ans_buf, 0, 0, &(qlist[ix]), (long)hlist);
338 		turnstate = State_EQueries;
339 		break;
340 	    case Qu_CharmGesture:
341 		jx = (int)(qlist[ix].rock);
342 		if (jx >= 128) {
343 		    spellnum = jx - 128;
344 		    jx = 1;
345 		}
346 		else {
347 		    spellnum = jx;
348 		    jx = 0;
349 		}
350 		sprintf(qu_buf, "What gesture do you want %s's %s hand to make?",
351 				NameOfBeing(gameval, QuVal_Target_Wizard,
352 				spellnum), (jx?"right":"left"));
353 		strcpy(ans_buf, "");
354 		add_answer(py, qu_buf, ans_buf, 0, 0, &(qlist[ix]), 0);
355 		turnstate = State_EQueries;
356 		break;
357 	    case Qu_WhichToDelay:
358 	    case Qu_WhichToPerm:
359 		/* use TLRightHand and TLLeftHand, since these queries always
360 		   show up by themselves */
361 		if (qlist[ix].qtype == Qu_WhichToDelay) {
362 		    tl = &(py->TLRightHand);
363 		    sprintf(qu_buf, "Which spell do you want to delay?");
364 		}
365 		else {
366 		    tl = &(py->TLLeftHand);
367 		    sprintf(qu_buf, "Which spell do you want to make permanent?");
368 		}
369 		hlist = (int *)qlist[ix].rock;
370 		tl->num = 0;
371 		for (jx=0; hlist[jx]!=(-1); jx++) {
372 		    add_to_targetlist(tl, spelllist[hlist[jx]].name, jx);
373 		}
374 		strcpy(ans_buf, "");
375 		add_answer(py, qu_buf, ans_buf, 0, 0, &(qlist[ix]), 0);
376 		turnstate = State_EQueries;
377 		break;
378 	    case Qu_SetOffDelay:
379 		sprintf(qu_buf, "Do you want to release the %s from the Delayed Effect?",
380 				spelllist[(int)qlist[ix].rock].name);
381 		strcpy(ans_buf, "No");
382 		add_answer(py, qu_buf, ans_buf, 1, 0, &(qlist[ix]), 0);
383 		turnstate = State_EQueries;
384 		break;
385 	    case Qu_ParalysisHand:
386 	    case Qu_CharmHand:
387 		if (qlist[ix].qtype == Qu_ParalysisHand)
388 		    sprintf(qu_buf, "Which of %s's hands do you want to paralyze?",
389 				NameOfBeing(gameval, QuVal_Target_Wizard,
390 				qlist[ix].rock));
391 		else
392 		    sprintf(qu_buf, "Which of %s's hands do you want to control?",
393 				NameOfBeing(gameval, QuVal_Target_Wizard,
394 				qlist[ix].rock));
395 		strcpy(ans_buf, "");
396 		add_answer(py, qu_buf, ans_buf, 0, 0, &(qlist[ix]), 0);
397 		break;
398 	    case Qu_ElementalType:
399 		sprintf(qu_buf, "Which type of elemental do you want to summon?");
400 		strcpy(ans_buf, "");
401 		add_answer(py, qu_buf, ans_buf, 0, 0, &(qlist[ix]), 0);
402 		break;
403 	    case Qu_MonsterTarget:
404 		jx = (int)(qlist[ix].rock);
405 		attnum = jx / 256;
406 		spellnum = jx % 256;
407 		switch (attnum) {
408 		    case 1:
409 			sprintf(qu_buf, "Whom do you want %s to attack?",
410 					NameOfBeing(gameval, QuVal_Target_Creature,
411 					spellnum));
412 			break;
413 		    case 2:
414 			sprintf(qu_buf, "Whom do you want %s's first attack to be at?",
415 					NameOfBeing(gameval, QuVal_Target_Creature,
416 					spellnum));
417 			break;
418 		    case 3:
419 			sprintf(qu_buf, "Whom do you want %s's second attack to be at?",
420 					NameOfBeing(gameval, QuVal_Target_Creature,
421 					spellnum));
422 			break;
423 		    default:
424 			sprintf(qu_buf, "ERROR: Query about %d (%d)", spellnum, attnum);
425 			break;
426 		}
427 		{
428 		    int numtargs = NumberOfTargets(gameval, QuVal_Target_Wizard);
429 		    strcpy(ans_buf, "nobody");
430 		    answer_init = 0;
431 		    for (jx=0; jx<numtargs; jx++) {
432 			kx = (IndexOfTarget(gameval, QuVal_Target_Wizard, jx) &
433 					~QuVal_Target_MASK);
434 			if (kx != pnum) {
435 			    answer_init = jx | QuVal_Target_Wizard;
436 			    strcpy(ans_buf, NameOfTarget(gameval,
437 					QuVal_Target_Wizard, jx));
438 			    break;
439 			}
440 		    }
441 		}
442 		add_answer(py, qu_buf, ans_buf, 1, answer_init, &(qlist[ix]), 0);
443 		break;
444 	    case Qu_TargetBeing:
445 	    case Qu_TargetBeingNone:
446 	    case Qu_TargetWizard:
447 	    case Qu_TargetWizardNone:
448 	    case Qu_TargetRaiseDead:
449 		jx = (int)(qlist[ix].rock);
450 		spellnum = jx & (~QuVal_Hand_MASK);
451 		if (jx & QuVal_Hand_Left)
452 		    handage = "with your left hand";
453 		else if (jx & QuVal_Hand_Right)
454 		    handage = "with your right hand";
455 		else if (jx & QuVal_Hand_Both)
456 		    handage = "with both hands";
457 		else
458 		    handage = "from the Delayed Effect";
459 		if (spellnum==SP__STAB)
460 		    sprintf(qu_buf, "Who do you want to stab at (%s)?", handage);
461 		else
462 		    sprintf(qu_buf, "Who do you want to cast %s at (%s)?",
463 				spelllist[spellnum].name, handage);
464 		if (spelllist[spellnum].selfcast) {
465 		    int numtargs = NumberOfTargets(gameval, QuVal_Target_Wizard);
466 		    strcpy(ans_buf, "nobody");
467 		    answer_init = 0;
468 		    for (jx=0; jx<numtargs; jx++) {
469 			kx = (IndexOfTarget(gameval, QuVal_Target_Wizard, jx) &
470 					~QuVal_Target_MASK);
471 			if (kx == pnum) {
472 			    answer_init = jx | QuVal_Target_Wizard;
473 			    strcpy(ans_buf, NameOfTarget(gameval,
474 					QuVal_Target_Wizard, jx));
475 			    if (StuffAboutTarget(gameval, QuVal_Target_Wizard,
476 					jx) & Stuff_INVISIBLE)
477 				strcat(ans_buf, " [invisible]");
478 			    break;
479 			}
480 		    }
481 		}
482 		else {
483 		    int numtargs = NumberOfTargets(gameval, QuVal_Target_Wizard);
484 		    strcpy(ans_buf, "nobody");
485 		    answer_init = 0;
486 		    for (jx=0; jx<numtargs; jx++) {
487 			kx = (IndexOfTarget(gameval, QuVal_Target_Wizard, jx) &
488 					~QuVal_Target_MASK);
489 			if (kx != pnum) {
490 			    answer_init = jx | QuVal_Target_Wizard;
491 			    strcpy(ans_buf, NameOfTarget(gameval,
492 					QuVal_Target_Wizard, jx));
493 			    if (StuffAboutTarget(gameval, QuVal_Target_Wizard,
494 					jx) & Stuff_INVISIBLE)
495 				strcat(ans_buf, " [invisible]");
496 			    break;
497 			}
498 		    }
499 		}
500 		add_answer(py, qu_buf, ans_buf, 1, answer_init, &(qlist[ix]), 0);
501 		turnstate = State_EQueries;
502 		break;
503 	    default:
504 		break;
505 	}
506     }
507 
508     if (!gotany)
509 	return;
510 
511     invent_target_lists();
512 
513     for (ix=0; ix<numplayers; ix++) {
514 	py = &(players[ix]);
515 	py->turn_done = !py->turn_active;
516     }
517     for (ix=0; ix<numplayers; ix++) {
518 	py = &(players[ix]);
519 	redraw_column(py);
520 	draw_button(py, 0, 1); /* redraw turn-end button */
521 	redraw_queries_only(py, 0);
522 	/*update_statlist(py);*/
523     }
524     mainloop();
525     for (ix=0; ix<numplayers; ix++) {
526 	py = &(players[ix]);
527 	for (jx=0; jx<py->siquery.nlines; jx++) {
528 	    py->answers[jx].query->answer = py->answers[jx].answer;
529 	}
530     }
531 }
532 
draw_query_menu(py)533 void draw_query_menu(py)
534 struct player *py;
535 {
536     int ix, jx;
537     int qtype = py->answers[py->query_hit].query->qtype;
538 
539     draw_frame(py, &py->query_rect);
540     if (qtype==Qu_CharmGesture) {
541 	int posx, posy, hand;
542 	posx = py->query_rect.x+20;
543 	posy = py->query_rect.y+20;
544 	hand = (strstr(py->answers[py->query_hit].qu_str, "right hand") ? 1 : 0);
545 	for (jx=0; jx<2; jx++)
546 	    for (ix=0; ix<4; ix++) {
547 		XCopyPlane(py->dpy, py->gesturebm[hand][jx*4+ix], py->win,
548 				py->blackgc, 0, 0, GEST_SIZE, GEST_SIZE,
549 				posx+ix*GEST_SPACE, posy+jx*GEST_SPACE, 1);
550 	    }
551     }
552     else {
553 	for (ix=0; ix<py->query_tl->num; ix++) {
554 	    XDrawImageString(py->dpy, py->win, py->blackgc, py->query_rect.x+16,
555 			py->query_rect.y + ix*(py->lineheight+QMENU_LEADING) +
556 			py->lineheight + QMENU_BORDER, py->query_tl->tnames[ix],
557 			strlen(py->query_tl->tnames[ix]));
558 	}
559     }
560 }
561 
in_query_box(py,xpos,ypos)562 int in_query_box(py, xpos, ypos)
563 struct player *py;
564 int xpos, ypos;
565 {
566     return (xpos>=QUERY_X && ypos>=QUERY_Y && xpos<QUERY_X+QUERY_W
567 	    && ypos<QUERY_Y+QUERY_H);
568 }
569 
query_hit(py,xpos,ypos,button)570 int query_hit(py, xpos, ypos, button)
571 struct player *py;
572 int xpos, ypos;
573 int button;
574 {
575     int hitq = (ypos-QUERY_Y) / py->query_hgt + py->siquery.top;
576     int ix;
577     static XCharStruct overall;
578     int direction, ascent, descent;
579 
580     if (!py->turn_active || py->turn_done)
581 	return ms_None;
582 
583     if (hitq<0 || hitq>=py->siquery.nlines)
584 	return ms_None;
585 
586     if (!py->answers[hitq].query)
587 	return ms_None;
588 
589     switch (py->answers[hitq].query->qtype) {
590 	case Qu_WhichToPerm:
591 	    py->query_tl = (&(py->TLLeftHand));
592 	    break;
593 	case Qu_WhichToDelay:
594 	    py->query_tl = (&(py->TLRightHand));
595 	    break;
596 	case Qu_LeftHand:
597 	    py->query_tl = (&(py->TLLeftHand));
598 	    break;
599 	case Qu_RightHand:
600 	    py->query_tl = (&(py->TLRightHand));
601 	    break;
602 	case Qu_ElementalType:
603 	    py->query_tl = (&TLElementalType);
604 	    break;
605 	case Qu_MonsterTarget:
606 	    py->query_tl = (&TLBeingNone);
607 	    break;
608 	case Qu_TargetBeing:
609 	    py->query_tl = (&TLBeing);
610 	    break;
611 	case Qu_TargetBeingNone:
612 	    py->query_tl = (&TLBeingNone);
613 	    break;
614 	case Qu_TargetWizard:
615 	    py->query_tl = (&TLWizard);
616 	    break;
617 	case Qu_TargetWizardNone:
618 	    py->query_tl = (&TLWizardNone);
619 	    break;
620 	case Qu_TargetRaiseDead:
621 	    py->query_tl = (&TLRaiseDead);
622 	    break;
623 	case Qu_ParalysisHand:
624 	case Qu_CharmHand:
625 	    py->query_tl = (&TLPickHand);
626 	    break;
627 	case Qu_SetOffDelay:
628 	    py->query_tl = (&TLNoYes);
629 	    break;
630 	case Qu_CharmGesture:
631 	    py->query_tl = NULL;
632 	    break;
633 	case Qu_SaveTranscript: /* special value defined in xspell.h */
634 	    py->query_tl = (&TLNoYes);
635 	    break;
636 	default:
637 	    return ms_None;
638 	    break;
639     }
640 
641     py->query_hit = hitq;
642 
643     if (py->answers[hitq].query->qtype==Qu_CharmGesture) {
644 	py->query_rect.w = 240;
645 	py->query_rect.h = 140;
646 	py->query_rect.x = xpos - py->query_rect.w/2;
647 	py->query_rect.y = ypos - py->query_rect.h/2;
648     }
649     else {
650 	int maxwid = 0;
651 	for (ix=0; ix<py->query_tl->num; ix++) {
652 	    XTextExtents(py->font, py->query_tl->tnames[ix],
653 			strlen(py->query_tl->tnames[ix]), &direction, &ascent,
654 			&descent, &overall);
655 	    if (overall.width > maxwid)
656 		maxwid = overall.width;
657 	}
658 	py->query_rect.w = maxwid + 32 + FRAME_SHADOW;
659 	py->query_rect.h = py->query_tl->num * (py->lineheight+QMENU_LEADING) +
660 			2*QMENU_BORDER+FRAME_SHADOW;
661 	py->query_rect.x = xpos - py->query_rect.w/2;
662 	py->query_rect.y = ypos - py->query_rect.h/2;
663     }
664     py->query_sel = (-1);
665     adjust_rect(&py->query_rect);
666     backing_store(py, &py->query_rect);
667     draw_query_menu(py);
668     query_motion(py, xpos, ypos, button);
669 
670     return ms_Query;
671 }
672 
query_motion(py,xpos,ypos,button)673 int query_motion(py, xpos, ypos, button)
674 struct player *py;
675 int xpos, ypos;
676 int button;
677 {
678     int hitrow;
679     int qtype = py->answers[py->query_hit].query->qtype;
680 
681     if (qtype==Qu_CharmGesture) {
682 	int posx, posy, hitx, hity;
683 
684 	posx = py->query_rect.x+20;
685 	posy = py->query_rect.y+20;
686 
687 	hitx = (xpos - posx + GEST_SPACE) / GEST_SPACE - 1;
688 	hity = (ypos - posy + GEST_SPACE) / GEST_SPACE - 1;
689 
690 	if (hitx>=0 && hitx<4 && hity>=0 && hity<2)
691 	    hitrow = hity*4 + hitx;
692 	else
693 	    hitrow = (-1);
694 
695 	if (hitrow==py->query_sel)
696 	    return;
697 
698 	if (py->query_sel != (-1)) {
699 	    /* erase old */
700 	    hitx = py->query_sel % 4;
701 	    hity = py->query_sel / 4;
702 	    XDrawRectangle(py->dpy, py->win, py->whitegc, posx+hitx*GEST_SPACE-1,
703 			posy+hity*GEST_SPACE-1, GEST_SIZE+1, GEST_SIZE+1);
704 	    XDrawRectangle(py->dpy, py->win, py->whitegc, posx+hitx*GEST_SPACE-2,
705 			posy+hity*GEST_SPACE-2, GEST_SIZE+3, GEST_SIZE+3);
706 	}
707 
708 	py->query_sel = hitrow;
709 
710 	if (py->query_sel != (-1)) {
711 	    /* draw new */
712 	    hitx = py->query_sel % 4;
713 	    hity = py->query_sel / 4;
714 	    XDrawRectangle(py->dpy, py->win, py->blackgc, posx+hitx*GEST_SPACE-1,
715 			posy+hity*GEST_SPACE-1, GEST_SIZE+1, GEST_SIZE+1);
716 	    XDrawRectangle(py->dpy, py->win, py->blackgc, posx+hitx*GEST_SPACE-2,
717 			posy+hity*GEST_SPACE-2, GEST_SIZE+3, GEST_SIZE+3);
718 	}
719     }
720     else {
721 	ypos -= (py->query_rect.y + QMENU_BORDER);
722 	if (ypos<0 || xpos < py->query_rect.x ||
723 			xpos >= py->query_rect.x+py->query_rect.w)
724 	    hitrow = (-1);
725 	else
726 	    hitrow = ypos / (py->lineheight+QMENU_LEADING);
727 
728 	if (hitrow<0 || hitrow>=py->query_tl->num)
729 	    hitrow = (-1);
730 
731 	if (hitrow==py->query_sel)
732 	    return;
733 
734 	if (py->query_sel != (-1)) {
735 	    /* erase old */
736 	    XDrawRectangle(py->dpy, py->win, py->whitegc,
737 			py->query_rect.x+QMENU_BORDER, py->query_rect.y +
738 			py->query_sel*(py->lineheight+QMENU_LEADING) +
739 			QMENU_BORDER, py->query_rect.w-(FRAME_SHADOW+2*QMENU_BORDER),
740 			py->lineheight+QMENU_LEADING);
741 	}
742 
743 	py->query_sel = hitrow;
744 
745 	if (py->query_sel != (-1)) {
746 	    /* draw new */
747 	    XDrawRectangle(py->dpy, py->win, py->blackgc,
748 			py->query_rect.x+QMENU_BORDER, py->query_rect.y +
749 			py->query_sel*(py->lineheight+QMENU_LEADING) +
750 			QMENU_BORDER, py->query_rect.w-(FRAME_SHADOW+2*QMENU_BORDER),
751 			py->lineheight+QMENU_LEADING);
752 	}
753     }
754 }
755 
query_release(py,xpos,ypos,button)756 int query_release(py, xpos, ypos, button)
757 struct player *py;
758 int xpos, ypos;
759 int button;
760 {
761     int qtype = py->answers[py->query_hit].query->qtype;
762     int ix, jx;
763 
764     backing_restore(py);
765     if (py->query_sel != (-1)) {
766 	if (qtype==Qu_CharmGesture) {
767 	    py->answers[py->query_hit].answer = py->query_sel;
768 	    py->answers[py->query_hit].done = 1;
769 	    strcpy(py->answers[py->query_hit].ans_str, gesture_name(py->query_sel));
770 	}
771 	else {
772 	    py->answers[py->query_hit].answer = py->query_tl->tnums[py->query_sel];
773 	    py->answers[py->query_hit].done = 1;
774 	    strcpy(py->answers[py->query_hit].ans_str, py->query_tl->tnames[py->query_sel]);
775 	    if (qtype==Qu_LeftHand || qtype==Qu_RightHand) {
776 		struct answer *ans = (&(py->answers[py->query_hit]));
777 		struct answer *anso;
778 		int *hlist = (int *)ans->rock;
779 		int *hlisto;
780 		int otherq;
781 		int forceans = (-1);
782 		struct target_list *othertl;
783 
784 		if (qtype==Qu_LeftHand) {
785 		    otherq = Qu_RightHand;
786 		    othertl = (&(py->TLRightHand));
787 		}
788 		else {
789 		    otherq = Qu_LeftHand;
790 		    othertl = (&(py->TLLeftHand));
791 		}
792 
793 		for (ix=0; ix<py->siquery.nlines; ix++) {
794 		    if (py->answers[ix].query->qtype == otherq) {
795 			anso = (&(py->answers[ix]));
796 			hlisto = (int *)anso->rock;
797 			if (hlist[py->query_sel+1] & QuVal_Hand_Both) {
798 			    /* force other hand to same spell */
799 			    for (jx=0; jx<hlisto[0]; jx++)
800 				if (hlist[py->query_sel+1] == hlisto[jx+1]) {
801 				    forceans = jx;
802 				    break;
803 				}
804 			}
805 			else {
806 			    /* should force other hand away from 2-handed
807 			       answer, but there is no case in the game where
808 			       this is a concern. */
809 			}
810 			if (forceans != (-1)) {
811 			    /*printf("Forcing q.%d to %d\n", ix, forceans);
812 			      fflush(stdout);*/
813 			    py->answers[ix].answer = othertl->tnums[forceans];
814 			    py->answers[ix].done = 1;
815 			    strcpy(py->answers[ix].ans_str, othertl->tnames[forceans]);
816 			}
817 		    }
818 		}
819 	    }
820 	}
821 	redraw_queries_only(py, 0);
822     }
823 }
824 
825