1 #include <stdio.h>
2 #include <string.h>
3 #include <sys/time.h>
4 #include <X11/Xlib.h>
5 #include <X11/Xutil.h>
6 #include "handwave.h"
7 #include "spelllist.h"
8 #include "xspell.h"
9
10 extern void redraw(), redraw_stats(), redraw_queries(), redraw_buttons(),
11 redraw_text(), redraw_column();
12 extern int gesture_hit();
13 void redraw_stats_only(), update_statlist();
14 void redraw_done_markers();
15
16 int blinklevel; /* in tenths of a second */
17
mainloop()18 void mainloop()
19 {
20 int pnum;
21 XEvent event;
22 int gotit, gotround;
23 struct player *py;
24 fd_set readbits;
25 int numsocks, sock;
26 int doneloop = 0;
27 char c;
28 struct timeval startround, now, pausetime;
29
30 blinklevel = 0;
31 for (pnum=0; pnum<numplayers; pnum++) {
32 players[pnum].mousestate = ms_None;
33 players[pnum].turn_blinklimit = (random() % 50) + 5;
34 players[pnum].turn_blinked = 0;
35 }
36 for (pnum=0; pnum<numplayers; pnum++)
37 update_statlist(&players[pnum]);
38 gettimeofday(&startround, NULL);
39
40 while (!doneloop) {
41 gotround = 0;
42 for (pnum=0; pnum<numplayers; pnum++) {
43 gotit = XCheckWindowEvent(players[pnum].dpy, players[pnum].win,
44 EVENTMASK, &event);
45 if (gotit) {
46 gotround = 1;
47 py = &(players[pnum]);
48 switch (event.type) {
49 case Expose:
50 do {
51 gotit = XCheckWindowEvent(players[pnum].dpy,
52 players[pnum].win, ExposureMask, &event);
53 } while (gotit);
54 py->gotexpose = 1;
55 redraw(py);
56 break;
57 case KeyPress:
58 if (1 == XLookupString(&event, &c, 1, NULL, NULL)) {
59 switch (c) {
60 case '\014': /* Ctrl-L */
61 XClearArea(py->dpy, py->win, 0, 0, 0, 0, 1);
62 break;
63 default:
64 talk_handle_char(py, c);
65 }
66 }
67 break;
68 case ButtonPress:
69 if (py->mousestate != ms_None) {
70 break;
71 }
72 if (in_gesture_box(py, event.xbutton.x, event.xbutton.y)) {
73 py->mousestate = gesture_hit(py, event.xbutton.x,
74 event.xbutton.y, event.xbutton.button);
75 py->mousebutton = event.xbutton.button;
76 }
77 else if (in_bbox_box(py, event.xbutton.x, event.xbutton.y)) {
78 py->mousestate = button_hit(py, event.xbutton.x,
79 event.xbutton.y, event.xbutton.button);
80 py->mousebutton = event.xbutton.button;
81 }
82 else if (in_scrollbar_box(&(py->sitext), event.xbutton.x,
83 event.xbutton.y)) {
84 py->mousestate = scrollbar_hit(&(py->sitext),
85 event.xbutton.x, event.xbutton.y,
86 event.xbutton.button);
87 py->mousebutton = event.xbutton.button;
88 }
89 else if (in_scrollbar_box(&(py->siquery), event.xbutton.x,
90 event.xbutton.y)) {
91 py->mousestate = scrollbar_hit(&(py->siquery),
92 event.xbutton.x, event.xbutton.y,
93 event.xbutton.button);
94 py->mousebutton = event.xbutton.button;
95 }
96 else if (in_scrollbar_box(&(py->sistats), event.xbutton.x,
97 event.xbutton.y)) {
98 py->mousestate = scrollbar_hit(&(py->sistats),
99 event.xbutton.x, event.xbutton.y,
100 event.xbutton.button);
101 py->mousebutton = event.xbutton.button;
102 }
103 else if (in_query_box(py, event.xbutton.x,
104 event.xbutton.y)) {
105 py->mousestate = query_hit(py, event.xbutton.x,
106 event.xbutton.y, event.xbutton.button);
107 py->mousebutton = event.xbutton.button;
108 }
109 else {
110 py->mousestate = ms_None;
111 }
112 break;
113 case MotionNotify:
114 switch (py->mousestate) {
115 case ms_Gesture:
116 gesture_motion(py, event.xbutton.x, event.xbutton.y,
117 event.xbutton.button);
118 break;
119 case ms_Scroll:
120 scrollbar_motion(py->scroll_active, event.xbutton.x,
121 event.xbutton.y, event.xbutton.button);
122 break;
123 case ms_Query:
124 query_motion(py, event.xbutton.x, event.xbutton.y,
125 event.xbutton.button);
126 break;
127 case ms_DoneBtn:
128 case ms_SpellBtn:
129 button_motion(py, event.xbutton.x, event.xbutton.y,
130 event.xbutton.button);
131 break;
132 default:
133 break;
134 }
135 break;
136 case ButtonRelease:
137 if (py->mousebutton == event.xbutton.button) {
138 switch (py->mousestate) {
139 case ms_Gesture:
140 gesture_release(py, event.xbutton.x,
141 event.xbutton.y, event.xbutton.button);
142 break;
143 case ms_Scroll:
144 scrollbar_release(py->scroll_active,
145 event.xbutton.x, event.xbutton.y,
146 event.xbutton.button);
147 break;
148 case ms_Query:
149 query_release(py, event.xbutton.x,
150 event.xbutton.y, event.xbutton.button);
151 break;
152 case ms_DoneBtn:
153 case ms_SpellBtn:
154 button_release(py, event.xbutton.x,
155 event.xbutton.y, event.xbutton.button);
156 break;
157 default:
158 break;
159 }
160 py->mousestate = ms_None;
161 }
162 break;
163 default:
164 break;
165 }
166 }
167 }
168 doneloop = 1;
169 for (pnum=0; pnum<numplayers; pnum++) {
170 if ((players[pnum].turn_active && !players[pnum].turn_done) ||
171 players[pnum].mousestate!=ms_None) {
172 doneloop = 0;
173 break;
174 }
175 }
176 {
177 /* check time */
178 long sofar;
179 gettimeofday(&now, NULL);
180 sofar = (now.tv_sec - startround.tv_sec) * 10 +
181 (now.tv_usec - startround.tv_usec) / 100000;
182 if (sofar > blinklevel) {
183 blinklevel = sofar;
184 for (pnum=0; pnum<numplayers; pnum++)
185 if (!players[pnum].turn_blinked
186 && blinklevel > players[pnum].turn_blinklimit) {
187 players[pnum].turn_blinked = 1;
188 redraw_done_markers(&(players[pnum]));
189 }
190 }
191 }
192 if (!gotround && !doneloop) {
193 /* no events -- wait a while */
194 FD_ZERO(&readbits);
195 numsocks = 0;
196 for (pnum=0; pnum<numplayers; pnum++) {
197 sock = ConnectionNumber(players[pnum].dpy);
198 if (sock+1 > numsocks)
199 numsocks = sock+1;
200 FD_SET(sock, &readbits);
201 XFlush(players[pnum].dpy);
202 }
203 pausetime.tv_sec = 0;
204 pausetime.tv_usec = 200000; /* 1/5th of a second */
205 (void)select(numsocks, &readbits, 0, 0, &pausetime);
206 }
207 }
208 }
209
redraw(py)210 void redraw(py)
211 struct player *py;
212 {
213 redraw_text(py);
214 redraw_column(py);
215 redraw_buttons(py);
216 redraw_queries(py);
217 redraw_stats(py);
218 redraw_talk(py);
219 if (py->backstore)
220 switch (py->mousestate) {
221 case ms_Gesture:
222 draw_gesture_menu(py);
223 break;
224 case ms_SpellBtn:
225 draw_spelllist(py);
226 break;
227 case ms_Query:
228 draw_query_menu(py);
229 break;
230 default:
231 break;
232 }
233 }
234
235 #define STATS_X (476)
236 #define STATS_Y (449)
237 #define STATS_W (324)
238 #define STATS_H (104)
239 #define STATS_HP (244)
240
init_stats(py)241 void init_stats(py)
242 struct player *py;
243 {
244 py->statlist_size = 4;
245 py->statlist = (struct statthing *)malloc(sizeof(struct statthing) * py->statlist_size);
246
247 py->sistats.nlines = 0;
248 py->sistats.visible = (STATS_H-2) / py->lineheight;
249 py->sistats.py = py;
250 py->sistats.top = 0;
251 py->sistats.lineheight = py->lineheight;
252 py->sistats.x = STATS_X;
253 py->sistats.y = STATS_Y;
254 py->sistats.h = STATS_H;
255 py->sistats.redraw = redraw_stats_only;
256 }
257
clear_stats(py)258 void clear_stats(py)
259 struct player *py;
260 {
261 py->sistats.nlines = 0;
262 py->sistats.top = 0;
263 }
264
add_statthing(py,index,type,hp,stuff)265 void add_statthing(py, index, type, hp, stuff)
266 struct player *py;
267 int index, type;
268 int hp;
269 long stuff;
270 {
271 int num;
272
273 if (py->sistats.nlines >= py->statlist_size) {
274 while (py->sistats.nlines >= py->statlist_size)
275 py->statlist_size *= 2;
276 py->statlist = (struct statthing *)realloc(py->statlist,
277 sizeof(struct statthing) * py->statlist_size);
278 }
279 num = py->sistats.nlines;
280 py->sistats.nlines++;
281 py->statlist[num].index = index;
282 py->statlist[num].type = type;
283 py->statlist[num].hp = hp;
284 py->statlist[num].stuff = stuff;
285 }
286
287 #define DRAWSTAR(py) ((py)->turn_active ? (py)->turn_done : (py)->turn_blinked)
288
redraw_done_markers(pdone)289 void redraw_done_markers(pdone)
290 struct player *pdone;
291 {
292 int pnum, pdonenum;
293 int ix, qline;
294 int ypos;
295
296 struct player *py;
297
298 pdonenum = (pdone-players);
299 for (pnum=0; pnum<numplayers; pnum++) {
300 py = &(players[pnum]);
301 for (ix=0; ix<py->sistats.visible; ix++) {
302 qline = py->sistats.top + ix;
303 if (qline >= py->sistats.nlines) break;
304 if (py->statlist[qline].type == QuVal_Target_Wizard
305 && py->statlist[qline].index == pdonenum)
306 break;
307 }
308 if (ix<py->sistats.visible
309 && !(qline >= py->sistats.nlines)) {
310 ypos = STATS_Y+ix*py->lineheight+py->lineheight;
311 py->gotexpose = 1;
312 if (!py->backstore) {
313 if (DRAWSTAR(pdone)) {
314 DrawStringField(py, "*", STATS_X+4, ypos, 12);
315 }
316 else {
317 DrawStringField(py, " ", STATS_X+4, ypos, 12);
318 }
319 }
320 }
321 }
322 }
323
redraw_stats_only(py,baronly)324 void redraw_stats_only(py, baronly)
325 struct player *py;
326 int baronly;
327 {
328 int ix, qline;
329 int ypos;
330 struct statthing *st;
331 char sbuf[32];
332 struct player *other;
333
334 if (!baronly) {
335 for (ix=0; ix<py->sistats.visible; ix++) {
336 qline = py->sistats.top + ix;
337 if (qline<0)
338 continue;
339 ypos = STATS_Y+ix*py->lineheight+py->lineheight;
340 if (qline >= py->sistats.nlines) {
341 DrawStringField(py, "", STATS_X+4, ypos, STATS_W-4);
342 }
343 else {
344 st = &(py->statlist[qline]);
345 if (st->type==QuVal_Target_Wizard) {
346 other = &(players[st->index]);
347 if (DRAWSTAR(other)) {
348 DrawStringField(py, "*", STATS_X+4, ypos, 12);
349 }
350 else {
351 DrawStringField(py, " ", STATS_X+4, ypos, 12);
352 }
353 DrawStringField(py, NameOfBeing(gameval, st->type, st->index),
354 STATS_X+16, ypos, STATS_W-16);
355 }
356 else {
357 DrawStringField(py, "", STATS_X+4, ypos, 20);
358 DrawStringField(py, NameOfBeing(gameval, st->type, st->index),
359 STATS_X+24, ypos, STATS_W-24);
360 }
361 sprintf(sbuf, "%d %s%s%s%s%s%s%s", st->hp,
362 (st->stuff & Stuff_INVISIBLE) ? "I" : "",
363 (st->stuff & Stuff_RESIST_HEAT) ? "H" : "",
364 (st->stuff & Stuff_RESIST_COLD) ? "C" : "",
365 (st->stuff & Stuff_PROTECT_EVIL) ? "P" : "",
366 (st->stuff & Stuff_BLIND) ? "b" : "",
367 (st->stuff & Stuff_DISEASE) ? "d" : "",
368 (st->stuff & Stuff_POISON) ? "p" : "");
369 DrawStringField(py, sbuf, STATS_X+STATS_HP, ypos, STATS_W-STATS_HP);
370 }
371 }
372 }
373
374 redraw_scrollbar(&(py->sistats));
375 }
376
redraw_stats(py)377 void redraw_stats(py)
378 struct player *py;
379 {
380 int ix;
381
382 XDrawRectangle(py->dpy, py->win, py->blackgc, STATS_X-3, STATS_Y-2,
383 STATS_W+4, STATS_H+3);
384 XDrawRectangle(py->dpy, py->win, py->blackgc, STATS_X-SCROLL_W, STATS_Y-2,
385 SCROLL_W-3, STATS_H+3);
386
387 redraw_stats_only(py, 0);
388 }
389
390 static int statthing_pnum;
391
statthing_compare(st1,st2)392 int statthing_compare(st1, st2)
393 struct statthing *st1, *st2;
394 {
395 int own1, own2;
396
397 if (st1->type==QuVal_Target_Wizard)
398 own1 = st1->index;
399 else
400 own1 = OwnerOfCreature(gameval, st1->index);
401 if (st2->type==QuVal_Target_Wizard)
402 own2 = st2->index;
403 else
404 own2 = OwnerOfCreature(gameval, st2->index);
405
406 if (own1 != own2) {
407 if (own1==(-1)) own1 = (-300);
408 else if (own1 == statthing_pnum)
409 own1 = (-200);
410 if (own2==(-1)) own2 = (-300);
411 else if (own2 == statthing_pnum)
412 own2 = (-200);
413 return (own1 - own2);
414 }
415
416 if (st1->type==QuVal_Target_Wizard && st2->type==QuVal_Target_Wizard)
417 return (0);
418 if (st1->type==QuVal_Target_Wizard)
419 return (-100);
420 if (st2->type==QuVal_Target_Wizard)
421 return (100);
422 return (st1->index - st2->index);
423 }
424
update_statlist(py)425 void update_statlist(py)
426 struct player *py;
427 {
428 int ix, max, hp;
429 long stuff;
430 clear_stats(py);
431
432 max = NumberOfBeings(gameval, QuVal_Target_Wizard);
433 for (ix=0; ix<max; ix++) {
434 hp = HitPointsOfBeing(gameval, QuVal_Target_Wizard, ix);
435 stuff = StuffAboutBeing(gameval, QuVal_Target_Wizard, ix);
436 if (hp>=0)
437 add_statthing(py, ix, QuVal_Target_Wizard, hp, stuff);
438 }
439 max = NumberOfBeings(gameval, QuVal_Target_Creature);
440 for (ix=0; ix<max; ix++) {
441 hp = HitPointsOfBeing(gameval, QuVal_Target_Creature, ix);
442 stuff = StuffAboutBeing(gameval, QuVal_Target_Creature, ix);
443 if (hp>=0)
444 add_statthing(py, ix, QuVal_Target_Creature, hp, stuff);
445 }
446
447 statthing_pnum = py-players;
448 qsort(py->statlist, py->sistats.nlines, sizeof(struct statthing), statthing_compare);
449
450 redraw_stats_only(py, 0);
451 }
452