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