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