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