rnd-19980930-3
[rocksndiamonds.git] / src / events.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  events.c                                                *
12 ***********************************************************/
13
14 #include "events.h"
15 #include "init.h"
16 #include "screens.h"
17 #include "tools.h"
18 #include "game.h"
19 #include "editor.h"
20 #include "misc.h"
21 #include "tape.h"
22 #include "joystick.h"
23
24 void EventLoop(void)
25 {
26   while(1)
27   {
28     if (XPending(display))      /* got event from X server */
29     {
30       XEvent event;
31
32       XNextEvent(display, &event);
33
34       switch(event.type)
35       {
36         case Expose:
37           HandleExposeEvent((XExposeEvent *) &event);
38           break;
39         case UnmapNotify:
40           SleepWhileUnmapped();
41           break;
42         case ButtonPress:
43         case ButtonRelease:
44           HandleButtonEvent((XButtonEvent *) &event);
45           break;
46         case MotionNotify:
47           HandleMotionEvent((XMotionEvent *) &event);
48           break;
49         case KeyPress:
50         case KeyRelease:
51           HandleKeyEvent((XKeyEvent *) &event);
52           break;
53         case FocusIn:
54         case FocusOut:
55           HandleFocusEvent((XFocusChangeEvent *) &event);
56           break;
57         case ClientMessage:
58           HandleClientMessageEvent((XClientMessageEvent *) &event);
59           break;
60         default:
61           break;
62       }
63     }
64     else                        /* got no event, but don't be lazy... */
65     {
66       HandleNoXEvent();
67
68       /* don't use all CPU time when idle; the main loop while playing
69          has its own synchronization and is CPU friendly, too */
70
71       if (game_status != PLAYING)
72       {
73         XSync(display, FALSE);
74         Delay(10);
75       }
76     }
77
78     if (game_status == EXITGAME)
79       return;
80   }
81 }
82
83 void ClearEventQueue()
84 {
85   while(XPending(display))
86   {
87     XEvent event;
88
89     XNextEvent(display, &event);
90
91     switch(event.type)
92     {
93       case Expose:
94         HandleExposeEvent((XExposeEvent *) &event);
95         break;
96       case UnmapNotify:
97         SleepWhileUnmapped();
98         break;
99       case ButtonRelease:
100         button_status = MB_RELEASED;
101         break;
102       case KeyRelease:
103         key_joystick_mapping = 0;
104         break;
105       case FocusIn:
106       case FocusOut:
107         HandleFocusEvent((XFocusChangeEvent *) &event);
108         break;
109       case ClientMessage:
110         HandleClientMessageEvent((XClientMessageEvent *) &event);
111         break;
112       default:
113         break;
114     }
115   }
116 }
117
118 void SleepWhileUnmapped()
119 {
120   BOOL window_unmapped = TRUE;
121
122   XAutoRepeatOn(display);
123
124   while(window_unmapped)
125   {
126     XEvent event;
127
128     XNextEvent(display, &event);
129
130     switch(event.type)
131     {
132       case Expose:
133         HandleExposeEvent((XExposeEvent *) &event);
134         break;
135       case ButtonRelease:
136         button_status = MB_RELEASED;
137         break;
138       case KeyRelease:
139         key_joystick_mapping = 0;
140         break;
141       case MapNotify:
142         window_unmapped = FALSE;
143         break;
144       case ClientMessage:
145         HandleClientMessageEvent((XClientMessageEvent *) &event);
146         break;
147       default:
148         break;
149     }
150   }
151
152   if (game_status==PLAYING)
153     XAutoRepeatOff(display);
154 }
155
156 void HandleExposeEvent(XExposeEvent *event)
157 {
158   int x = event->x, y = event->y;
159   int width = event->width, height = event->height;
160
161   if (direct_draw_on && game_status==PLAYING)
162   {
163     int xx,yy;
164     int x1 = (x-SX)/TILEX, y1 = (y-SY)/TILEY;
165     int x2 = (x-SX+width)/TILEX, y2 = (y-SY+height)/TILEY;
166
167     SetDrawtoField(DRAW_BACKBUFFER);
168
169     for(xx=0; xx<SCR_FIELDX; xx++)
170       for(yy=0; yy<SCR_FIELDY; yy++)
171         if (xx>=x1 && xx<=x2 && yy>=y1 && yy<=y2)
172           DrawScreenField(xx,yy);
173     DrawAllPlayers();
174
175     SetDrawtoField(DRAW_DIRECT);
176   }
177
178   if (soft_scrolling_on && game_status == PLAYING)
179   {
180     int fx = FX, fy = FY;
181
182     fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
183     fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 0);
184
185     XCopyArea(display,fieldbuffer,backbuffer,gc,
186               fx,fy, SXSIZE,SYSIZE,
187               SX,SY);
188   }
189
190   XCopyArea(display,drawto,window,gc, x,y, width,height, x,y);
191
192   XFlush(display);
193 }
194
195 void HandleButtonEvent(XButtonEvent *event)
196 {
197   motion_status = FALSE;
198
199   if (event->type==ButtonPress)
200     button_status = event->button;
201   else
202     button_status = MB_RELEASED;
203
204   HandleButton(event->x, event->y, button_status);
205 }
206
207 void HandleMotionEvent(XMotionEvent *event)
208 {
209   motion_status = TRUE;
210
211   HandleButton(event->x, event->y, button_status);
212 }
213
214 void HandleKeyEvent(XKeyEvent *event)
215 {
216   int key_status = (event->type == KeyPress ? KEY_PRESSED : KEY_RELEASED);
217   unsigned int event_state = (game_status != PLAYING ? event->state : 0);
218   KeySym key = XLookupKeysym(event, event_state);
219
220   HandleKey(key, key_status);
221 }
222
223 void HandleFocusEvent(XFocusChangeEvent *event)
224 {
225   static int old_joystick_status = -1;
226
227   if (event->type == FocusOut)
228   {
229     XAutoRepeatOn(display);
230     old_joystick_status = joystick_status;
231     joystick_status = JOYSTICK_OFF;
232     key_joystick_mapping = 0;
233   }
234   else if (event->type == FocusIn)
235   {
236     if (game_status == PLAYING)
237       XAutoRepeatOff(display);
238     if (old_joystick_status != -1)
239       joystick_status = old_joystick_status;
240   }
241 }
242
243 void HandleClientMessageEvent(XClientMessageEvent *event)
244 {
245   if ((event->window == window) &&
246       (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
247     CloseAll();
248 }
249
250 void HandleButton(int mx, int my, int button)
251 {
252   static int old_mx = 0, old_my = 0;
253
254   if (mx<0 || my<0)
255   {
256     mx = old_mx;
257     my = old_my;
258   }
259   else
260   {
261     old_mx = mx;
262     old_my = my;
263
264     HandleVideoButtons(mx,my,button);
265     HandleSoundButtons(mx,my,button);
266     HandleGameButtons(mx,my,button);
267   }
268
269 #ifdef DEBUG
270   if (game_status == PLAYING && !button)
271   {
272     int sx = (mx - SX) / TILEX;
273     int sy = (my - SY) / TILEY;
274
275     if (IN_VIS_FIELD(sx,sy))
276     {
277       int x = LEVELX(sx);
278       int y = LEVELY(sy);
279
280       printf("INFO: Feld[%d][%d] == %d\n", x,y, Feld[x][y]);
281       printf("      Store[%d][%d] == %d\n", x,y, Store[x][y]);
282       printf("      Store2[%d][%d] == %d\n", x,y, Store2[x][y]);
283       printf("      StorePlayer[%d][%d] == %d\n", x,y, StorePlayer[x][y]);
284       printf("      MovPos[%d][%d] == %d\n", x,y, MovPos[x][y]);
285       printf("      MovDir[%d][%d] == %d\n", x,y, MovDir[x][y]);
286       printf("      MovDelay[%d][%d] == %d\n", x,y, MovDelay[x][y]);
287       printf("\n");
288     }
289   }
290 #endif
291
292   switch(game_status)
293   {
294     case MAINMENU:
295       HandleMainMenu(mx,my,0,0,button);
296       break;
297     case TYPENAME:
298       HandleTypeName(0,XK_Return);
299       break;
300     case CHOOSELEVEL:
301       HandleChooseLevel(mx,my,0,0,button);
302       break;
303     case HALLOFFAME:
304       HandleHallOfFame(button);
305       break;
306     case LEVELED:
307       LevelEd(mx,my,button);
308       break;
309     case HELPSCREEN:
310       HandleHelpScreen(button);
311       break;
312     case SETUP:
313       HandleSetupScreen(mx,my,0,0,button);
314       break;
315     case PLAYING:
316       HandleGameActions(0);
317       break;
318     default:
319       break;
320   }
321 }
322
323 void HandleKey(KeySym key, int key_status)
324 {
325   int joy = 0;
326
327   /* Map cursor keys to joystick directions */
328
329   switch(key)
330   {
331     case XK_Left:               /* normale Richtungen */
332 #ifdef XK_KP_Left
333     case XK_KP_Left:
334 #endif
335     case XK_KP_4:
336 #ifndef MSDOS
337     case XK_J:
338 #endif
339     case XK_j:
340       joy |= JOY_LEFT;
341       break;
342     case XK_Right:
343 #ifdef XK_KP_Right
344     case XK_KP_Right:
345 #endif
346     case XK_KP_6:
347 #ifndef MSDOS
348     case XK_K:
349 #endif
350     case XK_k:
351       joy |= JOY_RIGHT;
352       break;
353     case XK_Up:
354 #ifdef XK_KP_Up
355     case XK_KP_Up:
356 #endif
357     case XK_KP_8:
358 #ifndef MSDOS
359     case XK_I:
360 #endif
361     case XK_i:
362       joy |= JOY_UP;
363       break;
364     case XK_Down:
365 #ifdef XK_KP_Down
366     case XK_KP_Down:
367 #endif
368     case XK_KP_2:
369 #ifndef MSDOS
370     case XK_M:
371 #endif
372     case XK_m:
373       joy |= JOY_DOWN;
374       break;
375 #ifdef XK_KP_Home
376     case XK_KP_Home:            /* Diagonalrichtungen */
377 #endif
378     case XK_KP_7:
379       joy |= JOY_UP | JOY_LEFT;
380       break;
381 #ifdef XK_KP_Page_Up
382     case XK_KP_Page_Up:
383 #endif
384     case XK_KP_9:
385       joy = JOY_UP | JOY_RIGHT;
386       break;
387 #ifdef XK_KP_End
388     case XK_KP_End:
389 #endif
390     case XK_KP_1:
391       joy |= JOY_DOWN | JOY_LEFT;
392       break;
393 #ifdef XK_KP_Page_Down
394     case XK_KP_Page_Down:
395 #endif
396     case XK_KP_3:
397       joy |= JOY_DOWN | JOY_RIGHT;
398       break;
399 #ifndef MSDOS
400     case XK_S:                  /* Feld entfernen */
401 #endif
402     case XK_s:
403       joy |= JOY_BUTTON_1 | JOY_LEFT;
404       break;
405 #ifndef MSDOS
406     case XK_D:
407 #endif
408     case XK_d:
409       joy |= JOY_BUTTON_1 | JOY_RIGHT;
410       break;
411 #ifndef MSDOS
412     case XK_E:
413 #endif
414     case XK_e:
415       joy |= JOY_BUTTON_1 | JOY_UP;
416       break;
417 #ifndef MSDOS
418     case XK_X:
419 #endif
420     case XK_x:
421       joy |= JOY_BUTTON_1 | JOY_DOWN;
422       break;
423     case XK_Shift_L:            /* Linker Feuerknopf */
424 #ifndef MSDOS
425     case XK_Control_L:
426     case XK_Alt_L:
427     case XK_Meta_L:
428 #endif
429       joy |= JOY_BUTTON_1;
430       break;
431     case XK_Shift_R:            /* Rechter Feuerknopf */
432 #ifndef MSDOS
433     case XK_Control_R:
434     case XK_Alt_R:
435     case XK_Meta_R:
436     case XK_Mode_switch:
437     case XK_Multi_key:
438     case XK_B:                  /* (Bombe legen) */
439 #endif
440     case XK_b:
441       joy |= JOY_BUTTON_2;
442       break;
443     default:
444       break;
445   }
446
447   if (joy)
448   {
449     if (key_status == KEY_PRESSED)
450       key_joystick_mapping |= joy;
451     else
452       key_joystick_mapping &= ~joy;
453
454     HandleJoystick();
455   }
456
457   if (game_status != PLAYING)
458     key_joystick_mapping = 0;
459
460   if (key_status == KEY_RELEASED)
461     return;
462
463   if (key==XK_Return && game_status==PLAYING && AllPlayersGone)
464   {
465     CloseDoor(DOOR_CLOSE_1);
466     game_status = MAINMENU;
467     DrawMainMenu();
468     return;
469   }
470
471   if (key==XK_Escape && game_status!=MAINMENU)  /* quick quit to MAINMENU */
472   {
473     CloseDoor(DOOR_CLOSE_1 | DOOR_NO_DELAY);
474     game_status = MAINMENU;
475     DrawMainMenu();
476     return;
477   }
478
479   if (game_status==PLAYING && (tape.playing || tape.pausing))
480     return;
481
482   switch(game_status)
483   {
484     case TYPENAME:
485       HandleTypeName(0,key);
486       break;
487     case MAINMENU:
488     case CHOOSELEVEL:
489     case SETUP:
490     {
491       switch(key)
492       {
493         case XK_Return:
494           if (game_status==MAINMENU)
495             HandleMainMenu(0,0,0,0,MB_MENU_CHOICE);
496           else if (game_status==CHOOSELEVEL)
497             HandleChooseLevel(0,0,0,0,MB_MENU_CHOICE);
498           else if (game_status==SETUP)
499             HandleSetupScreen(0,0,0,0,MB_MENU_CHOICE);
500           break;
501         default:
502           break;
503       }
504       break;
505     }
506     case HELPSCREEN:
507       HandleHelpScreen(MB_RELEASED);
508       break;
509     case HALLOFFAME:
510       switch(key)
511       {
512         case XK_Return:
513           game_status = MAINMENU;
514           DrawMainMenu();
515           BackToFront();
516           break;
517         default:
518           break;
519       }
520       break;
521     case LEVELED:
522       LevelNameTyping(key);
523       break;
524     case PLAYING:
525     {
526       switch(key)
527       {
528
529 #ifdef DEBUG
530         case XK_0:
531         case XK_1:
532         case XK_2:
533         case XK_3:
534         case XK_4:
535         case XK_5:
536         case XK_6:
537         case XK_7:
538         case XK_8:
539         case XK_9:
540           if (key == XK_0)
541             GameFrameDelay = 500;
542           else
543             GameFrameDelay = (key - XK_0) * 10;
544           printf("Game speed == %d%% (%d ms delay between two frames)\n",
545                  GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
546           break;
547
548         case XK_a:
549           if (ScrollStepSize == TILEX/8)
550             ScrollStepSize = TILEX/4;
551           else
552             ScrollStepSize = TILEX/8;
553           printf("ScrollStepSize == %d\n", ScrollStepSize);
554           break;
555
556         case XK_f:
557           ScrollStepSize = TILEX/8;
558           printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
559           break;
560         case XK_g:
561           ScrollStepSize = TILEX/4;
562           printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
563           break;
564         case XK_h:
565           ScrollStepSize = TILEX/2;
566           printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
567           break;
568         case XK_l:
569           ScrollStepSize = TILEX;
570           printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
571           break;
572
573 #ifndef MSDOS
574         case XK_Q:
575 #endif
576         case XK_q:
577           local_player->dynamite = 1000;
578           break;
579
580         case XK_x:
581
582           {
583             int i,j,k, num_steps = 8, step_size = TILEX / num_steps;
584             static long scroll_delay=0;
585             long scroll_delay_value = 4*4 / num_steps;
586
587             printf("Scroll test\n");
588
589             for(i=0;i<3;i++)
590             {
591               for(j=0;j<SCR_FIELDX;j++)
592               {
593                 for(k=0;k<num_steps;k++)
594                 {
595                   int xxx = j*TILEX+k*step_size;
596                   int done = 0;
597
598                   while(!done)
599                   {
600                     if (DelayReached(&scroll_delay, scroll_delay_value))
601                     {
602                       XCopyArea(display,fieldbuffer,window,gc,
603                                 SX+xxx,SY,
604                                 SXSIZE-xxx,SYSIZE,
605                                 SX,SY);
606                       XCopyArea(display,fieldbuffer,window,gc,
607                                 SX,SY,
608                                 xxx,SYSIZE,
609                                 SX+SXSIZE-xxx,SY);
610   
611                       XFlush(display);
612                       XSync(display,FALSE);
613
614                       done = 1;
615                     }
616                     else
617                     {
618                       Delay(1);
619                     }
620                   }
621   
622                   /*
623                   Delay(160 / num_steps);
624                   */
625                   /*
626                   Delay(120 / num_steps);
627                   */
628                 }
629               }
630             }
631           }
632
633           break;
634
635         case XK_y:
636           /*
637           {
638             printf("FX = %d, FY = %d\n", FX,FY);
639
640             XCopyArea(display,fieldbuffer,window,gc,
641                       0,0,
642                       MIN(WIN_XSIZE,FXSIZE),MIN(WIN_YSIZE,FYSIZE),
643                       0,0);
644             XFlush(display);
645             XSync(display,FALSE);
646             Delay(1000);
647           }
648           */
649
650           printf("direct_draw_on == %d\n", direct_draw_on);
651
652           break;
653
654         case XK_z:
655           {
656             int i;
657
658             for(i=0; i<MAX_PLAYERS; i++)
659             {
660               printf("Player %d:\n", i);
661               printf("  jx == %d, jy == %d\n",
662                      stored_player[i].jx, stored_player[i].jy);
663               printf("  last_jx == %d, last_jy == %d\n",
664                      stored_player[i].last_jx, stored_player[i].last_jy);
665             }
666             printf("\n");
667           }
668
669           break;
670
671         case XK_t:
672           {
673             char *color[] = { "yellow", "red", "green", "blue" };
674
675             do
676               TestPlayer = (TestPlayer + 1) % MAX_PLAYERS;
677             while(!stored_player[TestPlayer].active);
678
679             printf("TestPlayer = %d (%s player)\n",
680                    TestPlayer, color[TestPlayer]);
681           }
682
683           break;
684 #endif
685
686         default:
687           break;
688       }
689       break;
690     }
691     default:
692       break;
693   }
694 }
695
696
697
698 /* TEST STUFF -------------------------------------------------------------- */
699
700 #define PROT_VERS_1 1
701 #define PROT_VERS_2 0
702 #define PROT_VERS_3 1
703
704 #define OP_NICK 1
705 #define OP_PLAY 2
706 #define OP_FALL 3
707 #define OP_DRAW 4
708 #define OP_LOST 5
709 #define OP_GONE 6
710 #define OP_CLEAR 7
711 #define OP_NEW 8
712 #define OP_LINES 9
713 #define OP_GROW 10
714 #define OP_MODE 11
715 #define OP_LEVEL 12
716 #define OP_BOT 13
717 #define OP_KILL 14
718 #define OP_PAUSE 15
719 #define OP_CONT 16
720 #define OP_VERSION 17
721 #define OP_BADVERS 18
722 #define OP_MSG 19
723 #define OP_YOUARE 20
724 #define OP_LINESTO 21
725 #define OP_WON 22
726 #define OP_ZERO 23
727
728 /* server stuff */
729
730 #define BUFLEN 4096
731
732 extern int sfd;
733 extern unsigned char realbuf[], readbuf[], writbuf[];
734 extern unsigned char *buf;
735 extern int nread, nwrite;
736
737 extern void fatal(char *);
738 extern void flushbuf(void);
739 extern void sysmsg(char *);
740
741 /* like memcpy, but guaranteed to handle overlap when s <= t */
742 void copydown(char *s, char *t, int n)
743 {
744   for (; n; n--)
745     *(s++) = *(t++);
746 }
747
748 void handlemessages()
749 {
750   unsigned int len;
751   static char msgbuf[300];
752
753   while (nread >= 4 && nread >= 4 + readbuf[3])
754   {
755     len = readbuf[3];
756     if (readbuf[0] || readbuf[1] || readbuf[2])
757       fatal("Wrong server line length");
758
759     memcpy(buf, &readbuf[4], len);
760     nread -= 4 + len;
761     copydown(readbuf, readbuf + 4 + len, nread);
762
763     switch(buf[1])
764     {
765       case OP_YOUARE:
766         printf("OP_YOUARE: %d\n", buf[0]);
767         break;
768
769       case OP_NEW:
770         printf("OP_NEW: %d\n", buf[0]);
771         sprintf(msgbuf, "new client %d connected", buf[0]);
772         sysmsg(msgbuf);
773         break;
774       
775       case OP_GONE:
776         printf("OP_GONE: %d\n", buf[0]);
777         sprintf(msgbuf, "client %d disconnected", buf[0]);
778         sysmsg(msgbuf);
779         break;
780
781       case OP_BADVERS:
782         {
783           static char tmpbuf[128];
784
785           sprintf(tmpbuf, "Protocol version mismatch: server expects %d.%d.x instead of %d.%d.%d\n", buf[2], buf[3], PROT_VERS_1, PROT_VERS_2, PROT_VERS_3);
786           fatal(tmpbuf);
787         }
788         break;
789       
790       case OP_PLAY:
791         printf("OP_PLAY: %d\n", buf[0]);
792         sprintf(msgbuf, "client %d starts game", buf[0]);
793         sysmsg(msgbuf);
794         break;
795
796       case OP_PAUSE:
797         printf("OP_PAUSE: %d\n", buf[0]);
798         sprintf(msgbuf, "client %d pauses game", buf[0]);
799         sysmsg(msgbuf);
800         break;
801
802       case OP_CONT:
803         printf("OP_CONT: %d\n", buf[0]);
804         sprintf(msgbuf, "client %d continues game", buf[0]);
805         sysmsg(msgbuf);
806         break;
807
808       case OP_WON:
809         printf("OP_WON: %d\n", buf[0]);
810         sprintf(msgbuf, "client %d wins the game", buf[0]);
811         sysmsg(msgbuf);
812         break;
813
814       case OP_ZERO:
815         printf("OP_ZERO: %d\n", buf[0]);
816         sprintf(msgbuf, "client %d resets game counters", buf[0]);
817         sysmsg(msgbuf);
818         break;
819
820       case OP_NICK:
821         printf("OP_NICK: %d\n", buf[0]);
822         sprintf(msgbuf, "client %d calls itself %s", buf[0], &buf[2]);
823         sysmsg(msgbuf);
824         break;
825
826       case OP_MSG:
827         printf("OP_MSG: %d\n", buf[0]);
828         sprintf(msgbuf, "client %d sends message", buf[0]);
829         break;
830       
831       case OP_LOST:
832         printf("OP_MSG: %d\n", buf[0]);
833         sprintf(msgbuf, "client %d has lost", buf[0]);
834         break;
835       
836       case OP_LEVEL:
837         printf("OP_MSG: %d\n", buf[0]);
838         sprintf(msgbuf, "client %d sets level to %d", buf[0], buf[2]);
839         break;
840     }
841   }
842
843   fflush(stdout);
844 }
845
846
847
848 static void HandleNetworking()
849 {
850   static struct timeval tv = { 0, 0 };
851   fd_set rfds;
852   int r = 0;
853
854   if (standalone)
855     return;
856
857   flushbuf();
858
859   FD_ZERO(&rfds);
860   FD_SET(sfd, &rfds);
861
862   r = select(sfd + 1, &rfds, NULL, NULL, &tv);
863
864   if (r < 0 && errno != EINTR)
865   {
866     perror("select");
867     fatal("fatal: select() failed");
868   }
869
870   if (r < 0)
871     FD_ZERO(&rfds);
872
873   if (FD_ISSET(sfd, &rfds))
874   {
875     int r;
876
877     r = read(sfd, readbuf + nread, BUFLEN - nread);
878
879     if (r < 0)
880       fatal("Error reading from server");
881     if (r == 0)
882       fatal("Connection to server lost");
883     nread += r;
884
885     handlemessages();
886   }
887 }
888
889 void HandleNoXEvent()
890 {
891   if (button_status && game_status != PLAYING)
892   {
893     HandleButton(-1,-1,button_status);
894     return;
895   }
896
897   HandleNetworking();
898
899   switch(game_status)
900   {
901     case MAINMENU:
902     case CHOOSELEVEL:
903     case HALLOFFAME:
904     case HELPSCREEN:
905     case SETUP:
906       HandleJoystick();
907       break;
908     case PLAYING:
909       HandleJoystick();
910
911       /*
912       HandleGameActions(0);
913       */
914
915       break;
916     default:
917       break;
918   }
919 }
920
921 void HandleJoystick()
922 {
923   int joystick  = Joystick();
924   int keyboard  = key_joystick_mapping;
925
926   /*
927   int joy       = (tape.playing ? TapePlayAction() : (joystick | keyboard));
928   */
929
930   int joy       = (joystick | keyboard);
931   int left      = joy & JOY_LEFT;
932   int right     = joy & JOY_RIGHT;
933   int up        = joy & JOY_UP;
934   int down      = joy & JOY_DOWN;
935   int button    = joy & JOY_BUTTON;
936   int newbutton = (JoystickButton() == JOY_BUTTON_NEW_PRESSED);
937   int dx        = (left ? -1    : right ? 1     : 0);
938   int dy        = (up   ? -1    : down  ? 1     : 0);
939
940   switch(game_status)
941   {
942     case MAINMENU:
943     case CHOOSELEVEL:
944     case SETUP:
945     {
946       static long joystickmove_delay = 0;
947
948       if (joystick && !button && !DelayReached(&joystickmove_delay,15))
949         newbutton = dx = dy = 0;
950
951       if (game_status==MAINMENU)
952         HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
953       else if (game_status==CHOOSELEVEL)
954         HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
955       else if (game_status==SETUP)
956         HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
957       break;
958     }
959
960     case HALLOFFAME:
961       HandleHallOfFame(!newbutton);
962       break;
963
964     case HELPSCREEN:
965       HandleHelpScreen(!newbutton);
966       break;
967
968     case PLAYING:
969       if (tape.playing || keyboard)
970         newbutton = ((joy & JOY_BUTTON) != 0);
971
972       if (AllPlayersGone && newbutton)
973       {
974         CloseDoor(DOOR_CLOSE_1);
975         game_status = MAINMENU;
976         DrawMainMenu();
977         return;
978       }
979
980       if (tape.pausing || AllPlayersGone)
981         joy = 0;
982
983       HandleGameActions(joy);
984       break;
985
986     default:
987       break;
988   }
989 }